func GetRuntimeStats(channel chan *lib.RuntimeStatus, sleep time.Duration) { memStats := &runtime.MemStats{} lastSampleTime := time.Now() var lastPauseNs uint64 = 0 var lastNumGc uint32 = 0 var runtime_status lib.RuntimeStatus nsInMs := float64(time.Millisecond) for { runtime.ReadMemStats(memStats) now := time.Now() runtime_status.TimeString = lib.GetTimeString() runtime_status.Alloc = memStats.Alloc runtime_status.Sys = memStats.Sys runtime_status.Mallocs = memStats.Mallocs runtime_status.Frees = memStats.Frees runtime_status.HeapAlloc = memStats.HeapAlloc runtime_status.HeapSys = memStats.HeapSys runtime_status.HeapIdle = memStats.HeapIdle runtime_status.HeapInuse = memStats.HeapInuse runtime_status.HeapObjects = memStats.HeapObjects runtime_status.StackSys = memStats.StackSys runtime_status.StackInuse = memStats.StackInuse runtime_status.MSpanInuse = memStats.MSpanInuse runtime_status.MSpanSys = memStats.MSpanSys runtime_status.MCacheInuse = memStats.MCacheInuse runtime_status.MCacheSys = memStats.MCacheSys runtime_status.GCTotalPause = float64(memStats.PauseTotalNs) / nsInMs /* 计算平均每秒GC暂停的时间 */ // 总的GC暂停时间大于0 if lastPauseNs > 0 { // 获取两次GC间隔的时间 pauseSinceLastSample := memStats.PauseTotalNs - lastPauseNs runtime_status.GCPausePerSecond = float64(pauseSinceLastSample) / nsInMs / sleep.Seconds() } lastPauseNs = memStats.PauseTotalNs // 两次采样之间GC的次数 countGc := int(memStats.NumGC - lastNumGc) /* 计算平均每秒GC的次数 */ if lastNumGc > 0 { diff := float64(countGc) diffTime := now.Sub(lastSampleTime).Seconds() runtime_status.GCPerSecond = diff / diffTime } /* 如果两次采样之间发生了GC,则获取暂停时间(ms) */ if countGc > 0 { /* 如果两次采样之间发生了超过256次的GC,就有可能获取不到一些GC动作的暂停时间 因为memStats.PauseNS是一个环形的缓存,最多只能记录256次GC动作的暂停时间 */ if countGc > 256 { fmt.Fprintf(os.Stderr, "We're missing some gc pause times") countGc = 256 } for i := 0; i < countGc; i++ { // 最近一次的GC暂停时间保存在[(NumGC+255)%256] idx := int((memStats.NumGC-uint32(i))+255) % 256 pause := float64(memStats.PauseNs[idx]) // 暂停时间单位为ns,ns/nsInMs单位为ms runtime_status.GCPause = pause / nsInMs } } // 记录前一次的状态,为下次采样做准备 lastNumGc = memStats.NumGC lastSampleTime = now channel <- &runtime_status time.Sleep(sleep) } }
func GetLoadInfo(channel chan *lib.LoadInfo, sleep time.Duration) { var load_info lib.LoadInfo for { meminfo_file := "/proc/meminfo" meminfo_data, err := lib.ReadFileFullContentByLine(meminfo_file) if err != nil { log.Fatal(err) return } now_time := lib.GetTimeString() load_info.TimeString = now_time meminfo_total_splited := bytes.Fields(meminfo_data[0]) meminfo_free_splited := bytes.Fields(meminfo_data[1]) meminfo_buffers_splited := bytes.Fields(meminfo_data[2]) meminfo_cached_splited := bytes.Fields(meminfo_data[3]) if v, err := strconv.ParseUint(string(meminfo_total_splited[1]), 10, 0); err == nil { load_info.MemTotal = v } if v, err := strconv.ParseUint(string(meminfo_free_splited[1]), 10, 0); err == nil { load_info.MemFree = v } if v, err := strconv.ParseUint(string(meminfo_buffers_splited[1]), 10, 0); err == nil { load_info.MemBuffers = v } if v, err := strconv.ParseUint(string(meminfo_cached_splited[1]), 10, 0); err == nil { load_info.MemCached = v } load_info.MemUsed = load_info.MemTotal - load_info.MemFree loadavg_file := "/proc/loadavg" loadavg_data, err := lib.ReadFileFullContent(loadavg_file) if err != nil { log.Fatal(err) return } loadavg_splited := strings.Split(string(loadavg_data), " ") if len(loadavg_splited) > 0 { // 1分钟内的负载 load1 := strings.Trim(loadavg_splited[0], " ") if v, err := strconv.ParseFloat(load1, 64); err == nil { load_info.LoadAVG1 = v } // 5分钟内的负载 load5 := strings.Trim(loadavg_splited[1], " ") if v, err := strconv.ParseFloat(load5, 64); err == nil { load_info.LoadAVG5 = v } // 15分钟内的负载 load15 := strings.Trim(loadavg_splited[2], " ") if v, err := strconv.ParseFloat(load15, 64); err == nil { load_info.LoadAVG15 = v } } channel <- &load_info time.Sleep(sleep) } }
// 获取进程的信息 func GetProcessInfo(channel chan *lib.ProcessInfo, sleep time.Duration) { /* Process's memory status in /proc/PID/statm: total program pages | resident pages | shared pages | text(code) | data/stack | library | dirty pages page size is 4K */ var process_info lib.ProcessInfo pagesize := int64(os.Getpagesize()) for { pid := os.Getpid() statm_file := fmt.Sprintf("/proc/%d/statm", pid) data, err := lib.ReadFileFullContent(statm_file) if err != nil { log.Fatal(err) return } now_time := lib.GetTimeString() process_info.TimeString = now_time memory_splited := strings.Split(string(data), " ") if len(memory_splited) > 0 { // 虚拟内存(VIRT) virtual_pages := strings.Trim(memory_splited[0], " ") if v, err := strconv.ParseInt(virtual_pages, 10, 0); err == nil { process_info.VirtualMemory = v * pagesize } // 物理内存(RES) resisdent_pages := strings.Trim(memory_splited[1], " ") if v, err := strconv.ParseInt(resisdent_pages, 10, 0); err == nil { process_info.ResisdentMemory = v * pagesize } // 共享内存(SHR) shared_pages := strings.Trim(memory_splited[2], " ") if v, err := strconv.ParseInt(shared_pages, 10, 0); err == nil { process_info.SharedMemory = v * pagesize } } // 进程运行了多长时间 process_info.Uptime = int64(time.Now().Sub(lib.StartTime).Seconds()) channel <- &process_info time.Sleep(sleep) } }