303 lines
7.3 KiB
Plaintext
303 lines
7.3 KiB
Plaintext
/*
|
|
* Copyright (c) 2018 Alastair Roy Poole <netstar@gmail.com>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#if defined(__OpenBSD__)
|
|
# define CPU_STATES 6
|
|
#else
|
|
# define CPU_STATES 5
|
|
#endif
|
|
|
|
static int
|
|
cpu_count(void)
|
|
{
|
|
static int cores = 0;
|
|
|
|
if (cores != 0)
|
|
return cores;
|
|
|
|
#if defined(__linux__)
|
|
char buf[4096];
|
|
FILE *f;
|
|
int line = 0;
|
|
|
|
f = fopen("/proc/stat", "r");
|
|
if (!f) return 0;
|
|
|
|
while (fgets(buf, sizeof(buf), f))
|
|
{
|
|
if (line)
|
|
{
|
|
if (!strncmp(buf, "cpu", 3))
|
|
cores++;
|
|
else
|
|
break;
|
|
}
|
|
line++;
|
|
}
|
|
|
|
fclose(f);
|
|
#elif defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
|
size_t len;
|
|
int mib[2] = { CTL_HW, HW_NCPU };
|
|
|
|
len = sizeof(cores);
|
|
if (sysctl(mib, 2, &cores, &len, NULL, 0) < 0)
|
|
return 0;
|
|
#endif
|
|
return cores;
|
|
}
|
|
|
|
int
|
|
system_cpu_count_get(void)
|
|
{
|
|
return cpu_count();
|
|
}
|
|
|
|
int
|
|
system_cpu_online_count_get(void)
|
|
{
|
|
#if defined(__OpenBSD__)
|
|
static int cores = 0;
|
|
|
|
if (cores != 0) return cores;
|
|
|
|
size_t len;
|
|
int mib[2] = { CTL_HW, HW_NCPUONLINE };
|
|
|
|
len = sizeof(cores);
|
|
if (sysctl(mib, 2, &cores, &len, NULL, 0) < 0)
|
|
return cpu_count();
|
|
|
|
return cores;
|
|
#else
|
|
return cpu_count();
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
_cpu_state_get(cpu_core_t **cores, int ncpu)
|
|
{
|
|
int diff_total, diff_idle;
|
|
double ratio, percent;
|
|
unsigned long total, idle, used;
|
|
cpu_core_t *core;
|
|
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
|
size_t size;
|
|
int i, j;
|
|
|
|
if (!ncpu)
|
|
return;
|
|
size = sizeof(unsigned long) * (CPU_STATES * ncpu);
|
|
unsigned long cpu_times[ncpu][CPU_STATES];
|
|
|
|
if (sysctlbyname("kern.cp_times", cpu_times, &size, NULL, 0) < 0)
|
|
return;
|
|
|
|
for (i = 0; i < ncpu; i++) {
|
|
core = cores[i];
|
|
unsigned long *cpu = cpu_times[i];
|
|
|
|
total = 0;
|
|
for (j = 0; j < CPU_STATES; j++)
|
|
total += cpu[j];
|
|
|
|
idle = cpu[4];
|
|
|
|
diff_total = total - core->total;
|
|
diff_idle = idle - core->idle;
|
|
if (diff_total == 0) diff_total = 1;
|
|
|
|
ratio = diff_total / 100.0;
|
|
used = diff_total - diff_idle;
|
|
percent = used / ratio;
|
|
|
|
if (percent > 100) percent = 100;
|
|
else if (percent < 0)
|
|
percent = 0;
|
|
|
|
core->percent = percent;
|
|
core->total = total;
|
|
core->idle = idle;
|
|
}
|
|
#elif defined(__OpenBSD__)
|
|
static struct cpustats cpu_times[CPU_STATES];
|
|
static int cpu_time_mib[] = { CTL_KERN, KERN_CPUSTATS, 0 };
|
|
size_t size;
|
|
int i, j;
|
|
|
|
memset(&cpu_times, 0, CPU_STATES * sizeof(struct cpustats));
|
|
if (!ncpu)
|
|
return;
|
|
|
|
for (i = 0; i < ncpu; i++) {
|
|
core = cores[i];
|
|
size = sizeof(struct cpustats);
|
|
cpu_time_mib[2] = i;
|
|
if (sysctl(cpu_time_mib, 3, &cpu_times[i], &size, NULL, 0) < 0)
|
|
return;
|
|
|
|
total = 0;
|
|
for (j = 0; j < CPU_STATES; j++)
|
|
total += cpu_times[i].cs_time[j];
|
|
|
|
idle = cpu_times[i].cs_time[CP_IDLE];
|
|
|
|
diff_total = total - core->total;
|
|
if (diff_total == 0) diff_total = 1;
|
|
|
|
diff_idle = idle - core->idle;
|
|
ratio = diff_total / 100.0;
|
|
used = diff_total - diff_idle;
|
|
percent = used / ratio;
|
|
|
|
if (percent > 100) percent = 100;
|
|
else if (percent < 0)
|
|
percent = 0;
|
|
|
|
core->percent = percent;
|
|
core->total = total;
|
|
core->idle = idle;
|
|
}
|
|
#elif defined(__linux__)
|
|
char *buf, name[128];
|
|
int i;
|
|
|
|
buf = file_contents("/proc/stat");
|
|
if (!buf) return;
|
|
|
|
for (i = 0; i < ncpu; i++) {
|
|
core = cores[i];
|
|
snprintf(name, sizeof(name), "cpu%d", i);
|
|
char *line = strstr(buf, name);
|
|
if (line)
|
|
{
|
|
line = strchr(line, ' ') + 1;
|
|
unsigned long cpu_times[4] = { 0 };
|
|
|
|
if (4 != sscanf(line, "%lu %lu %lu %lu", &cpu_times[0],
|
|
&cpu_times[1], &cpu_times[2], &cpu_times[3]))
|
|
return;
|
|
|
|
total = cpu_times[0] + cpu_times[1] + cpu_times[2] + cpu_times[3];
|
|
idle = cpu_times[3];
|
|
diff_total = total - core->total;
|
|
if (diff_total == 0) diff_total = 1;
|
|
|
|
diff_idle = idle - core->idle;
|
|
ratio = diff_total / 100.0;
|
|
used = diff_total - diff_idle;
|
|
percent = used / ratio;
|
|
|
|
if (percent > 100) percent = 100;
|
|
else if (percent < 0)
|
|
percent = 0;
|
|
|
|
core->percent = percent;
|
|
core->total = total;
|
|
core->idle = idle;
|
|
}
|
|
}
|
|
free(buf);
|
|
#elif defined(__MacOS__)
|
|
mach_msg_type_number_t count;
|
|
processor_cpu_load_info_t load;
|
|
mach_port_t mach_port;
|
|
unsigned int cpu_count;
|
|
int i;
|
|
|
|
cpu_count = ncpu;
|
|
|
|
count = HOST_CPU_LOAD_INFO_COUNT;
|
|
mach_port = mach_host_self();
|
|
if (host_processor_info(mach_port, PROCESSOR_CPU_LOAD_INFO, &cpu_count,
|
|
(processor_info_array_t *)&load, &count) != KERN_SUCCESS)
|
|
exit(-1);
|
|
|
|
for (i = 0; i < ncpu; i++) {
|
|
core = cores[i];
|
|
|
|
total = load[i].cpu_ticks[CPU_STATE_USER] +
|
|
load[i].cpu_ticks[CPU_STATE_SYSTEM] +
|
|
load[i].cpu_ticks[CPU_STATE_IDLE] +
|
|
load[i].cpu_ticks[CPU_STATE_NICE];
|
|
idle = load[i].cpu_ticks[CPU_STATE_IDLE];
|
|
|
|
diff_total = total - core->total;
|
|
if (diff_total == 0) diff_total = 1;
|
|
diff_idle = idle - core->idle;
|
|
ratio = diff_total / 100.0;
|
|
used = diff_total - diff_idle;
|
|
percent = used / ratio;
|
|
|
|
if (percent > 100) percent = 100;
|
|
else if (percent < 0)
|
|
percent = 0;
|
|
|
|
core->percent = percent;
|
|
core->total = total;
|
|
core->idle = idle;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
cpu_core_t **
|
|
system_cpu_usage_delayed_get(int *ncpu, int usecs)
|
|
{
|
|
cpu_core_t **cores;
|
|
int i;
|
|
|
|
*ncpu = cpu_count();
|
|
|
|
cores = malloc((*ncpu) * sizeof(cpu_core_t *));
|
|
|
|
for (i = 0; i < *ncpu; i++)
|
|
cores[i] = calloc(1, sizeof(cpu_core_t));
|
|
|
|
_cpu_state_get(cores, *ncpu);
|
|
usleep(usecs);
|
|
_cpu_state_get(cores, *ncpu);
|
|
|
|
return cores;
|
|
}
|
|
|
|
cpu_core_t **
|
|
system_cpu_usage_get(int *ncpu)
|
|
{
|
|
return system_cpu_usage_delayed_get(ncpu, 1000000);
|
|
}
|
|
|
|
int
|
|
system_cpu_frequency_get(void)
|
|
{
|
|
int freq = -1;
|
|
|
|
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
|
size_t len = sizeof(freq);
|
|
if (sysctlbyname("dev.cpu.0.freq", &freq, &len, NULL, 0) != -1)
|
|
freq *= 1000;
|
|
#elif defined(__OpenBSD__)
|
|
int mib[2] = { CTL_HW, HW_CPUSPEED };
|
|
size_t len = sizeof(freq);
|
|
if (sysctl(mib, sizeof(mib), &freq, &len, NULL, 0) != -1)
|
|
freq *= 1000;
|
|
#elif defined(__linux__)
|
|
|
|
#else
|
|
|
|
#endif
|
|
return freq;
|
|
}
|