
// gcc -o /tmp/burn cpuBurningMulticore.c -lm -lpthread

// ATTENTION : NE COMPILEZ PAS AVEC LES OPTIONS D'OPTIMISATION !!!!

// Execution : /tmp/burn <Mhz_you_want> <mask_core>
// Examples :
// cerin@zinzolin:~/Desktop$ /tmp/burn 2000 1 15: you want 2GHZ on CPU 1 for 15s
// cerin@zinzolin:~/Desktop$ /tmp/burn 2000 0 15: you want 2GHZ on CPU 0 for 15s
// cerin@zinzolin:~/Desktop$ /tmp/burn 2000 2 15: you want 2GHZ on CPU 2 for 15s
//
/// On a 4 cores Xeon processors @ 3GHZ:
// cerin@zinzolin:~/Desktop$ /tmp/burn 2000 3 15: you want 2GHZ on CPU 3
// Then stat top to check the processor activity:
//top - 15:47:39 up 36 days, 16 min,  3 users,  load average: 0.68, 0.58, 0.36
//Tasks: 168 total,   1 running, 159 sleeping,   5 stopped,   3 zombie
//Cpu0  :  0.7%us,  1.0%sy,  0.0%ni, 98.4%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
//Cpu1  :  0.3%us,  0.0%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
//Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
//Cpu3  :  1.9%us, 36.4%sy,  0.0%ni, 61.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

// Initial idea: the Wrekavoc tool at http://wrekavoc.gforge.inria.fr/

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sched.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <netdb.h>
#include <signal.h>

int
burn (int percent)
{
  struct sched_param max;

  struct timeval tv1, tv2;
  struct timezone tz1, tz2;
  long int factor, time;
  int m;

  if (percent < 0 || percent > 99)
    {
      printf ("Percentage not valid!\n");
      return (-1);
    }

  printf("Burned percentage: %d%\n",percent);

  max.sched_priority = sched_get_priority_max (SCHED_FIFO);
  //printf("priority=%d\n",max.sched_priority);
  if (sched_setscheduler (0, SCHED_FIFO, &max) == -1)
      {
        perror ("sched_setscheduler");
      }

  percent += 1;
  factor = 1;
  time = 0;
  while (time / (percent * 1000) < .50)
    {
      m = 0;
      factor *= 2;
      gettimeofday (&tv1, &tz1);
      while (m < factor)
	m++;
      gettimeofday (&tv2, &tz2);
      time =
	(tv2.tv_usec - tv1.tv_usec) + 1000000 * (tv2.tv_sec - tv1.tv_sec);
    }

      printf("time = %ld micro s\t\tfactor = %ld\ttime/(percent * 1000) =%ldms\n",time,factor,time/(percent * 1000));

  while (1)
    {

      m = 0;
      gettimeofday (&tv1, &tz1);
      while (m < factor)
	m++;
      gettimeofday (&tv2, &tz2);
      //printf("while : %ld  micro s\n",((tv2.tv_usec-tv1.tv_usec)+1000000 * (tv2.tv_sec - tv1.tv_sec)));
      //printf("usleep : %ld  micro s\n",((tv2.tv_usec-tv1.tv_usec)+1000000 * (tv2.tv_sec - tv1.tv_sec))*(100-percent)/percent);
      usleep (((tv2.tv_usec - tv1.tv_usec) +
	       1000000 * (tv2.tv_sec - tv1.tv_sec)) * (100 -
						       percent) / percent);
    }
  return 0;
}

/*
 * Return the percentage of CPU that is necessary to consume mghertz 
 * (mega-hertz) of the available Mhz on the current processor.
 */
int
mainburn (int Mymghertz, int CoreNumber)
{
  int AvailableMhz = 0;
  int proc;
  FILE *f;
  char mylig[256];
  int i;

  f = fopen ("/proc/cpuinfo", "r");
  //   cpu MHz         : 2992.774

  // We start to locate the core number
  fgets (mylig, 256, f);
  proc = (int) (ceil (atof (mylig + 11)));
  //printf("core=%s\n",mylig);
  while (!feof(f) && (proc != CoreNumber)) {
    for (i = 0; i < 23; i++)
      fgets (mylig, 256, f);
    fgets (mylig, 256, f);
    proc = (int) (ceil (atof (mylig + 11)));
    //printf("core=%s\n",mylig);
  }
  if (feof(f)) {
    printf("Core number (%d) not found\n",CoreNumber);
    exit(1);
  }
  //   this info is located 6 line below 
  for (i = 0; i < 6; i++)
    fgets (mylig, 256, f);
  fclose (f);
  // printf("%s",mylig+11);
  AvailableMhz = (int) (ceil (atof (mylig + 11)));

  // printf("%d %d %8.6f\n",AvailableMhz,Mymghertz,ceil(100.0*((double)(AvailableMhz - Mymghertz)/(double)AvailableMhz)));

  if (AvailableMhz < Mymghertz)
    {
      perror ("not a valid request");
      return (0);
    }
  else
    return (int) (ceil
		  (100.0 *
		   ((double) (AvailableMhz - Mymghertz) /
		    (double) AvailableMhz)));
}


int
main (int argc, char *argv[])
{
  int i, j, k, l, pid, status;
  pthread_t       th1;
  void           *ret;
  unsigned long mask; 

  //sleep (5);

  if(argc != 4) {
    printf("Usage: need 4 arguments !\n");
    printf("/tmp/burn 2000 1 30: you want 2GHZ on CPU 1 for 30s\n");
    exit(1);
  }

  i = atoi (argv[1]);
  k = atoi (argv[2]);
  l = atoi (argv[3]);

  /* bind process to processor k */
  mask = (int)pow((float)2.0,(float)k);
  if (sched_setaffinity(0, sizeof(mask), &mask) <0) {
        perror("Problem with sched_setaffinity");
  }

  j = mainburn (i,k);
  pid=fork();
  if (pid == 0) { /* fils */
     printf("PID pere=%d\n",pid);
     printf("PID pere getpid=%d\n",getpid());

     sleep(l);

     kill(getppid(),SIGQUIT);
  } else {
     printf("PID fils =%d\n",pid);
     printf("PID fils getpid=%d\n",getpid());
      burn(j);
  }


  //if (pthread_create(&th1, NULL, (void *) burn, j) < 0) {
  //			fprintf(stderr, "pthread_create error for thread 1\n");
  //			exit(1);
  //		}
  //pthread_setaffinity_np(k);
  //(void) pthread_join(th1, &ret); /// On bloque

  return 0;
}
