Skip to content

Instantly share code, notes, and snippets.

@cpackham
Created March 7, 2021 22:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cpackham/6356a3a943accebb228135dc10daf721 to your computer and use it in GitHub Desktop.
Save cpackham/6356a3a943accebb228135dc10daf721 to your computer and use it in GitHub Desktop.
/**
* @file cpuload.c
*
* Simple binary that creates CPU load. This allows developers to artificially
* induce a specified level of CPU load (e.g. to test how well certain code
* responds under high load).
*
* Copyright 2008 Allied Telesis Labs, New Zealand
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <string.h>
#include <sys/time.h>
#include <pthread.h>
#define MAX_CPUS 64
static uint32_t msec_delay = UINT32_MAX;
static uint32_t cpu_util = 20;
static uint32_t
diff_time_in_ms (struct timeval start, struct timeval end)
{
uint32_t elapsed_ms;
/* get any difference in secs since epoch first, then the difference
* in microsecs will be the elapsed time (convert everything to ms) */
elapsed_ms = (end.tv_sec - start.tv_sec) * 1000;
elapsed_ms += end.tv_usec / 1000;
elapsed_ms -= start.tv_usec / 1000;
return elapsed_ms;
} /* diff_time_in_ms */
static void
do_tight_loop_for_100ms (uint32_t utilisation)
{
uint32_t elapsed_ms = 0;
uint32_t remainder;
struct timeval start, now;
remainder = (100 - utilisation) * 1000;
gettimeofday (&start, NULL);
/* go into a tight loop continually checking the time.
* we want to eat up the CPU for <utilisation> ms out of every 100 ms */
while (elapsed_ms < utilisation)
{
gettimeofday (&now, NULL);
elapsed_ms = diff_time_in_ms (start, now);
}
/* sleep the remainder */
usleep (remainder);
}
static void *
gobble_cpu (void *unused)
{
struct sched_param sched_param;
uint32_t elapsed_ms;
struct timeval start, now;
/* set our priority REALLY low */
sched_param.sched_priority = 1;
sched_setscheduler (0, SCHED_RR, &sched_param);
/* now cause the cpu load - loop until we've used up the desired CPU */
gettimeofday (&start, NULL);
elapsed_ms = 0;
while (elapsed_ms <= msec_delay)
{
/* go into a tight loop to eat up the CPU for 100 ms */
do_tight_loop_for_100ms (cpu_util);
/* check how much longer we need to loop for */
gettimeofday (&now, NULL);
elapsed_ms = diff_time_in_ms (start, now);
}
return NULL;
}
int
main (int argc, char *argv[])
{
pthread_t cputhread[MAX_CPUS];
int cpu;
int num_cpus;
if (argc >= 2)
{
/* get the CPU utilization % specified (default 20%) */
cpu_util = atoi (argv[1]);
/* print help if needed */
if (strstr (argv[1], "?") != NULL ||
strstr (argv[1], "help") != NULL || cpu_util > 100)
{
fprintf (stderr, "Usage: %s CPU-utilization [duration-ms]\n"
"Default: 20%% [no-timeout]\n", argv[0]);
return EXIT_FAILURE;
}
}
if (argc >= 3)
{
/* get the msec delay specified (default no timeout) */
msec_delay = atoi (argv[2]);
}
for (cpu = 1; cpu < MAX_CPUS; cpu++)
{
char cpupath[80];
snprintf (cpupath, sizeof (cpupath), "/sys/devices/system/cpu/cpu%d", cpu);
/* out of CPU cores? */
if (access (cpupath, F_OK) < 0)
{
break;
}
/* Create a new thread */
pthread_create (&cputhread[cpu], NULL, gobble_cpu, NULL);
}
num_cpus = cpu;
/* Finally, chew up CPU in the main thread */
gobble_cpu (NULL);
/* Wait for threads to exit */
for (cpu = 1; cpu < num_cpus; cpu++)
{
pthread_join (cputhread[cpu], NULL);
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment