In aim to test robustest of one of our products, we would like to consume a particular percent of CPU. This usage necessitate no specific hardware and is a good example of usage of PID in real world. How to achieve this?

We can use a loop to consume CPU and stop it after an amount of time:

 clock_gettime(CLOCK_REALTIME, &startwork);
 do {
     clock_gettime(CLOCK_REALTIME, &endwork);
 }  while (timediff(&endwork, &startwork) < x);

Now, we split time in periods of same size. Each period will be composed of two part: one to consume CPU (twork) and one to sleep (tsleep):

for (;;) {
  clock_gettime(CLOCK_REALTIME, &startwork);
  tsleep = period - twork;
  do {
      clock_gettime(CLOCK_REALTIME, &endwork);
  }  while (timediff(&endwork, &startwork) < twork);
  usleep(tsleep);
}

period should be small enough to have smooth usage of CPU. Nevertheless, you choose it smaller than 1 / HZ, there were risk of overhead due to contexts switches. I suggest to use 1ms to 100ms.

we now need to compute twork. twork = period * objective looks a good start. Nevertheless, it is not robust. What happens if we are preempted during our loop or if our period does not run exact time? We need to compute exact amount of CPU used and correct twork. So, we need use famous a PID regulator:

 static float compute_correction(float objective) {
   struct timespec w;
   clock_gettime(CLOCK_REALTIME, &w);
   struct rusage u;
   getrusage(RUSAGE_SELF, &u);    
   
   static long time_prev = 0;
   long time_cur = w.tv_sec * 1000000  + w.tv_nsec / 1000;
   static long usage_prev = 0;
   long usage_cur = (u.ru_utime.tv_sec + u.ru_stime.tv_sec) * 1000000  + (u.ru_utime.tv_usec + u.ru_stime.tv_usec);
   static float Ep = 0.;
   static float Ei = 0.;
   static float Ed = 0.;
   static const float Kp = 0.2;
   static const float Ki = 0.2;
   static const float Kd = 0.;
   
   //not enough samples taken (it's the first one!)
   if (time_prev == 0) {
       usage_prev = usage_cur;
       time_prev = time_cur;
       return 0.;
   }
   
   // Wait at least 25ms to be sure usage time is updated
   if (time_prev + 25000 > time_cur) 
       return  0.;
   
   Ed = (objective - (float) (usage_cur - usage_prev) / (float) (time_cur - time_prev)) - Ep;
   Ep += Ed;
   Ei += Ep;
   //printf("(p:%f i:%f d:%f), usage:(%ld / %ld)\n", Ep, Ei, Ed, (usage_cur - usage_prev), (time_cur - time_prev));
   
   usage_prev = usage_cur;
   time_prev = time_cur;
   
   return  Kp * (Ep + Ki * Ei + Kd * Ed);
 }

Sure, values of Kp, Ki, and Kd could (should) be tuned.

We now have to add this correction to twork:

 out = objective;
 for (;;) {
       ...
       out += compute_correction(objective);
       
       //adjust work and sleep time slices
       twork = period * out;
       if (twork > period)
           twork = period;
       if (twork < 0)
           twork = 0;
       tsleep = period - twork;
       ...
 }

To improve correctness, we also increase priority of our process:

   struct sched_param tSp;
   tSp.sched_priority = 90;
   if (sched_setscheduler(0, SCHED_RR, &tSp) < 0) 
       fprintf(stderr, "Warning: Unable to set Scheduler: %s (Are you root?)\n", strerror(errno));

Result can be found there