<commit_before>package mpmulticore

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphDef = map[string]mp.Graphs{
	"multicore.cpu.#": {
		Label: "MultiCore CPU",
		Unit:  "percentage",
		Metrics: []mp.Metrics{
			{Name: "user", Label: "user", Diff: false, Stacked: true},
			{Name: "nice", Label: "nice", Diff: false, Stacked: true},
			{Name: "system", Label: "system", Diff: false, Stacked: true},
			{Name: "idle", Label: "idle", Diff: false, Stacked: true},
			{Name: "iowait", Label: "ioWait", Diff: false, Stacked: true},
			{Name: "irq", Label: "irq", Diff: false, Stacked: true},
			{Name: "softirq", Label: "softirq", Diff: false, Stacked: true},
			{Name: "steal", Label: "steal", Diff: false, Stacked: true},
			{Name: "guest", Label: "guest", Diff: false, Stacked: true},
			{Name: "guest_nice", Label: "guest_nice", Diff: false, Stacked: true},
		},
	},
	"multicore.loadavg_per_core": {
		Label: "MultiCore loadavg5 per core",
		Unit:  "float",
		Metrics: []mp.Metrics{
			{Name: "loadavg5", Label: "loadavg5", Diff: false, Stacked: false},
		},
	},
}

type saveItem struct {
	LastTime       time.Time
	ProcStatsByCPU map[string]procStats
}

type procStats struct {
	User      *float64 `json:"user"`
	Nice      *float64 `json:"nice"`
	System    *float64 `json:"system"`
	Idle      *float64 `json:"idle"`
	IoWait    *float64 `json:"iowait"`
	Irq       *float64 `json:"irq"`
	SoftIrq   *float64 `json:"softirq"`
	Steal     *float64 `json:"steal"`
	Guest     *float64 `json:"guest"`
	GuestNice *float64 `json:"guest_nice"`
	Total     float64  `json:"total"`
}

type cpuPercentages struct {
	GroupName string
	User      *float64
	Nice      *float64
	System    *float64
	Idle      *float64
	IoWait    *float64
	Irq       *float64
	SoftIrq   *float64
	Steal     *float64
	Guest     *float64
	GuestNice *float64
}

func parseFloats(values []string) ([]float64, error) {
	var result []float64
	for _, v := range values {
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return nil, err
		}
		result = append(result, f)
	}
	return result, nil
}

func fill(arr []float64, elementCount int) []*float64 {
	var filled []*float64
	for _, v := range arr {
		copy := v
		filled = append(filled, &copy)
	}

	if len(arr) < elementCount {
		emptyArray := make([]*float64, elementCount-len(arr))
		filled = append(filled, emptyArray...)
	}
	return filled
}

func parseProcStat(out io.Reader) (map[string]procStats, error) {
	scanner := bufio.NewScanner(out)
	var result = make(map[string]procStats)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "cpu") {
			fields := strings.Fields(line)
			key := fields[0]
			values := fields[1:]

			// skip total cpu usage
			if key == "cpu" {
				continue
			}

			floatValues, err := parseFloats(values)
			if err != nil {
				return nil, err
			}

			total := 0.0
			for _, v := range floatValues {
				total += v
			}

			filledValues := fill(floatValues, 10)

			result[key] = procStats{
				User:      filledValues[0],
				Nice:      filledValues[1],
				System:    filledValues[2],
				Idle:      filledValues[3],
				IoWait:    filledValues[4],
				Irq:       filledValues[5],
				SoftIrq:   filledValues[6],
				Steal:     filledValues[7],
				Guest:     filledValues[8],
				GuestNice: filledValues[9],
				Total:     total,
			}
		} else {
			break
		}
	}
	return result, nil
}

func collectProcStatValues() (map[string]procStats, error) {
	file, err := os.Open("/proc/stat")
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return parseProcStat(file)
}

func saveValues(tempFileName string, values map[string]procStats, now time.Time) error {
	f, err := os.Create(tempFileName)
	if err != nil {
		return err
	}
	defer f.Close()

	s := saveItem{
		LastTime:       now,
		ProcStatsByCPU: values,
	}

	encoder := json.NewEncoder(f)
	err = encoder.Encode(s)
	if err != nil {
		return err
	}<commit_msg>use continue statement to reduce the indent count<commit_after>package mpmulticore

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphDef = map[string]mp.Graphs{
	"multicore.cpu.#": {
		Label: "MultiCore CPU",
		Unit:  "percentage",
		Metrics: []mp.Metrics{
			{Name: "user", Label: "user", Diff: false, Stacked: true},
			{Name: "nice", Label: "nice", Diff: false, Stacked: true},
			{Name: "system", Label: "system", Diff: false, Stacked: true},
			{Name: "idle", Label: "idle", Diff: false, Stacked: true},
			{Name: "iowait", Label: "ioWait", Diff: false, Stacked: true},
			{Name: "irq", Label: "irq", Diff: false, Stacked: true},
			{Name: "softirq", Label: "softirq", Diff: false, Stacked: true},
			{Name: "steal", Label: "steal", Diff: false, Stacked: true},
			{Name: "guest", Label: "guest", Diff: false, Stacked: true},
			{Name: "guest_nice", Label: "guest_nice", Diff: false, Stacked: true},
		},
	},
	"multicore.loadavg_per_core": {
		Label: "MultiCore loadavg5 per core",
		Unit:  "float",
		Metrics: []mp.Metrics{
			{Name: "loadavg5", Label: "loadavg5", Diff: false, Stacked: false},
		},
	},
}

type saveItem struct {
	LastTime       time.Time
	ProcStatsByCPU map[string]procStats
}

type procStats struct {
	User      *float64 `json:"user"`
	Nice      *float64 `json:"nice"`
	System    *float64 `json:"system"`
	Idle      *float64 `json:"idle"`
	IoWait    *float64 `json:"iowait"`
	Irq       *float64 `json:"irq"`
	SoftIrq   *float64 `json:"softirq"`
	Steal     *float64 `json:"steal"`
	Guest     *float64 `json:"guest"`
	GuestNice *float64 `json:"guest_nice"`
	Total     float64  `json:"total"`
}

type cpuPercentages struct {
	GroupName string
	User      *float64
	Nice      *float64
	System    *float64
	Idle      *float64
	IoWait    *float64
	Irq       *float64
	SoftIrq   *float64
	Steal     *float64
	Guest     *float64
	GuestNice *float64
}

func parseFloats(values []string) ([]float64, error) {
	var result []float64
	for _, v := range values {
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return nil, err
		}
		result = append(result, f)
	}
	return result, nil
}

func fill(arr []float64, elementCount int) []*float64 {
	var filled []*float64
	for _, v := range arr {
		copy := v
		filled = append(filled, &copy)
	}

	if len(arr) < elementCount {
		emptyArray := make([]*float64, elementCount-len(arr))
		filled = append(filled, emptyArray...)
	}
	return filled
}

func parseProcStat(out io.Reader) (map[string]procStats, error) {
	scanner := bufio.NewScanner(out)
	var result = make(map[string]procStats)
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.HasPrefix(line, "cpu") {
			continue
		}

		fields := strings.Fields(line)
		key := fields[0]
		values := fields[1:]

		// skip total cpu usage
		if key == "cpu" {
			continue
		}

		floatValues, err := parseFloats(values)
		if err != nil {
			return nil, err
		}

		total := 0.0
		for _, v := range floatValues {
			total += v
		}

		filledValues := fill(floatValues, 10)

		result[key] = procStats{
			User:      filledValues[0],
			Nice:      filledValues[1],
			System:    filledValues[2],
			Idle:      filledValues[3],
			IoWait:    filledValues[4],
			Irq:       filledValues[5],
			SoftIrq:   filledValues[6],
			Steal:     filledValues[7],
			Guest:     filledValues[8],
			GuestNice: filledValues[9],
			Total:     total,
		}
	}
	return result, nil
}

func collectProcStatValues() (map[string]procStats, error) {
	file, err := os.Open("/proc/stat")
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return parseProcStat(file)
}

func saveValues(tempFileName string, values map[string]procStats, now time.Time) error {
	f, err := os.Create(tempFileName)
	if err != nil {
		return err
	}
	defer f.Close()

	s := saveItem{
		LastTime:       now,
		ProcStatsByCPU: values,
	}

	encoder := json.NewEncoder(f)
	err = encoder.Encode(s)
	if err != nil {
		return err
	}
{'fraction_non_alphanumeric': 0.15322680540071845, 'fraction_numerical': 0.01858045336306206, 'mean_word_length': 3.4387025838372733, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2482289', 'n_tokens_mistral': 3309, 'n_tokens_neox': 2982, 'n_words': 768}