Skip to content

Instantly share code, notes, and snippets.

@frma71
Last active August 29, 2015 14:22
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 frma71/706410acbd31556dbbfa to your computer and use it in GitHub Desktop.
Save frma71/706410acbd31556dbbfa to your computer and use it in GitHub Desktop.
/* This is a tiny application to demonstrate the bug where the linux kernel reports
* load far greater then 100% for a single thread. It assumes CONFIG_HZ_100 and probably
* that NO_HZ is disabled. Since the kernel is sampling it doesn't reproduce the problem
* to its full extent every time, but on my arndale board it does so at least nine times
* out of ten.
*
* Compile with: gcc -o loadbug loadbug.c
*/
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/times.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
uint64_t clk(void) {
struct timespec ts;
int rv;
rv = clock_gettime(CLOCK_MONOTONIC, &ts);
assert(rv == 0);
return (uint64_t)ts.tv_sec*1000000000ULL + ts.tv_nsec;
}
void wait_for_tick(void) {
clock_t now = times(0);
while(now == times(0));
}
void busydelay(uint64_t ns) {
volatile int i;
uint64_t start = clk();
while(clk() - start < ns)
for(i = 0; i < 2000; i++) {}
}
void sysbusydelay(uint64_t ns) {
static int fd = -1;
static char buff[4096*100];
uint64_t start;
if(fd == -1)
fd = open("/dev/zero", O_RDONLY);
assert(fd >= 0);
start = clk();
while(clk() - start < ns) {
read(fd, buff, sizeof(buff));
}
}
void clk_sleep_until(uint64_t t) {
struct timespec ts;
int rv;
ts.tv_sec = t/1000000000ULL;
ts.tv_nsec = t - ts.tv_sec*1000000000ULL;
rv = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, 0);
assert(rv == 0);
}
#define NS_PER_US 1000ULL
#define NS_PER_MS 1000000ULL
#define NS_PER_SEC 1000000000ULL
#define NS_PER_TICK (10*NS_PER_MS)
int main(void) {
uint64_t t;
int i;
/* First synchronize with the tick
*/
wait_for_tick();
/* Wait until 1ms before the next tick.
*/
t = clk() + 9*NS_PER_MS;
clk_sleep_until(t);
while(1) {
/* Let system clock sample us once in system mode
*/
sysbusydelay(2*NS_PER_MS); /* sys-time during tick */
t += NS_PER_TICK;
clk_sleep_until(t);
/* ... and keep loading but not during tick-sampling
*/
for(i = 0; i < 10*100-1; i++) {
clk_sleep_until(t+2*NS_PER_MS); /* Make sure we are idle during tick() sampling */
busydelay(2*NS_PER_MS);
t += NS_PER_TICK;
clk_sleep_until(t);
}
printf("switch to umode\n");
/* Now utime hits every tick but the actual load is still 10%
*/
for(i = 0; i < 10*100; i++) {
busydelay(2*NS_PER_MS); /* Make sure we are running in user mode during tick() sampling */
t += NS_PER_TICK;
clk_sleep_until(t);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment