/**
 * \fn void main (void)
 * \brief Création du compteur "nom_compteur" dans /opt/productivity_link
 * \return EXIT_SUCCESS code de statut : ok. 
 * 
 */
int main (void) {
  /** Le type uuid permet de donner un identificateur au compteur */  
  uuid_t uuid; 
  
  unsigned long long nombre=0 ;
  int pld = PL_INVALID_DESCRIPTOR;
  
  /** Le nom du compteur est stocké
   * dans une constante de pointeur de chaine de caractères
   * const char *counter[].
   */
  const char *counter[] = {"grandeur_a_analyser"};
  
  /// Ouverture et test du compteur.
  if ((pld = pl_open("nom_compteur",1,counter,&uuid)) != PL_INVALID_DESCRIPTOR){
    
    /// Incrémentation de "nombre" jusqu'à 21.
    while (nombre<=21){
      pl_write(pld,&nombre,0);
      nombre++;
      sleep(1);
    }

    /// Décrémentation de "nombre" jusqu'à 5.
    while (nombre>5){
      nombre--;
      pl_write(pld,&nombre,0);
      sleep(1);
    }
    
    /// Fermeture du compteur
    pl_close(pld);
  }
  
  return EXIT_SUCCESS;
}
/*---------------------------------------------------------------------------
Function: main
Purpose : benchmark entry point
In      : none
Out     : none
Return  : status

History
----------------------------------------------------------------------------
Date        : Author                  Modification
----------------------------------------------------------------------------
04/16/2009    Jamel Tayeb             Creation.
*/
int main(void) {

    //----------------------------------------------------------------------
    // timing data
    //----------------------------------------------------------------------
#ifdef __PL_WINDOWS__
    __int64 start_counter = 0;
    __int64 stop_counter = 0;
    __int64 average_counter = 0;
    __int64 base_average_cycles = 0;
    __int64 pl_write_average_cycles = 0;
    __int64 pl_read_average_cycles = 0;
#endif // __PL_WINDOWS__
#if defined (__PL_LINUX__) || (__PL_SOLARIS__) || (__PL_MACOSX__)
    unsigned long long start_counter = 0;
    unsigned long long stop_counter = 0;
    unsigned long long average_counter = 0;
    unsigned long long base_average_cycles = 0;
    unsigned long long pl_write_average_cycles = 0;
    unsigned long long pl_read_average_cycles = 0;
#endif // __PL_LINUX__ || __PL_SOLARIS__ || __PL_MACOSX__

    //----------------------------------------------------------------------
    // Test PL data
    //----------------------------------------------------------------------
    PL_STATUS ret = PL_FAILURE;
    int pld = PL_INVALID_DESCRIPTOR;
    uuid_t uuid;
    char application_name[] = "benchmark";
    const char *counter_names[] = { "test_counter" };
    unsigned int counter_count = 1;
    unsigned long long i = 0;
    unsigned long long x = 0;
    int j = 0;

    //-----------------------------------------------------------------------
    // open test PL
    //-----------------------------------------------------------------------
    fprintf(stdout, "\n");
    fprintf(stdout, "************************************************************\n");
    fprintf(stdout, "* This micro-benchmark uses RDTSC / _IA64_REG_AR_ITC to    *\n");
    fprintf(stdout, "* evaluate the processor cycles required to carry-out the  *\n");
    fprintf(stdout, "* pl_write() and pl_read() Productivity Link API calls     *\n");
#ifdef __PL_WINDOWS__
    fprintf(stdout, "* (%12I64u write and read operations are performed    *\n", (unsigned long long)(MAX_ITERATIONS * MAX_OPERATIONS));
#endif // __PL_WINDOWS__
#if defined (__PL_LINUX__) || (__PL_SOLARIS__) || (__PL_MACOSX__)
    fprintf(stdout, "* (%12llu write and read operations are performed    *\n", (unsigned long long)(MAX_ITERATIONS * MAX_OPERATIONS));
#endif // __PL_LINUX__ || __PL_SOLARIS__ || __PL_MACOSX__
    fprintf(stdout, "* in sequence).                                            *\n");
    fprintf(stdout, "*                                                          *\n");
    fprintf(stdout, "* This method is imperfect as it will catch cycles         *\n");
    fprintf(stdout, "* consumed by interrupt routines.  Therefore, consider     *\n");
    fprintf(stdout, "* numbers as indications, not exact values.                *\n");
    fprintf(stdout, "* When running the benchmark, stop all other applications. *\n");
    fprintf(stdout, "*                                                          *\n");
    fprintf(stdout, "* When compiling the benchmark, deactivate all compiler    *\n");
    fprintf(stdout, "* optimizations.  Run in single processor configuration.   *\n");
    fprintf(stdout, "* Deactivate all frequency and voltage adjustment          *\n");
    fprintf(stdout, "* features before running this micro-benchmark.            *\n");
    fprintf(stdout, "************************************************************\n");
    fprintf(stdout, "\n");

    fprintf(stdout, "Opening Test PL:\n");
    pld = pl_open(application_name, counter_count, counter_names, &uuid);
    assert(pld != PL_INVALID_DESCRIPTOR);

    //-- test zone ----------------------------------------------------------

    /*
    @@@@@    @@    @@@@  @@@@@@         @@@@@ @@@@@@  @@@@   @@@@@
    @    @  @  @  @    @ @                @   @      @    @    @
    @    @ @    @ @      @                @   @      @         @
    @@@@@  @    @  @@@@  @@@@@@           @   @@@@@@  @@@@     @
    @    @ @@@@@@      @ @                @   @           @    @
    @    @ @    @      @ @                @   @           @    @
    @@@@@  @    @ @@@@@  @@@@@@           @   @@@@@@ @@@@@     @
    */
    //-----------------------------------------------------------------------
    // reference loop
    //-----------------------------------------------------------------------
    init_average();
    fprintf(stdout, "Measuring Base Data       : ");
    for(j = 0; j < MAX_ITERATIONS; j++) {
        fprintf(stdout, "*");
        start_timer();
        for(i = 0; i < MAX_OPERATIONS; i++) {
            ;
        }
        stop_timer();
        x = i; // consume i in case optimization is activated
        sum_average();
    }
    print_timer();
    fprintf(stdout, "\n");
    compute_average(MAX_ITERATIONS * MAX_OPERATIONS);
    base_average_cycles = average_counter;

    /*
    @    @ @@@@@  @@@@@   @@@@@ @@@@@@         @@@@@ @@@@@@  @@@@   @@@@@
    @    @ @    @   @       @   @                @   @      @    @    @
    @  @ @ @    @   @       @   @                @   @      @         @
    @  @ @ @@@@@    @       @   @@@@@@           @   @@@@@@  @@@@     @
    @  @ @ @  @     @       @   @                @   @           @    @
     @ @ @ @   @    @       @   @                @   @           @    @
      @ @  @    @ @@@@@     @   @@@@@@           @   @@@@@@ @@@@@     @
    */
    //----------------------------------------------------------------------
    // write loop
    //----------------------------------------------------------------------
    init_average();
    fprintf(stdout, "Measuring pl_write() Data : ");
    for(j = 0; j < MAX_ITERATIONS; j++) {
        fprintf(stdout, "*");
        start_timer();
        for(i = 0; i < MAX_OPERATIONS; i++) {
            pl_write(pld, &i, 0);
        }
        stop_timer();
        sum_average();
    }
    print_timer();
    fprintf(stdout, "\n");
    compute_average(MAX_ITERATIONS * MAX_OPERATIONS);
    pl_write_average_cycles = average_counter;

    /*
    @@@@@  @@@@@@   @@   @@@@@          @@@@@ @@@@@@  @@@@   @@@@@
    @    @ @       @  @  @    @           @   @      @    @    @
    @    @ @      @    @ @    @           @   @      @         @
    @@@@@  @@@@@@ @    @ @    @           @   @@@@@@  @@@@     @
    @  @   @      @@@@@@ @    @           @   @           @    @
    @   @  @      @    @ @    @           @   @           @    @
    @    @ @@@@@@ @    @ @@@@@            @   @@@@@@ @@@@@     @
    */
    //----------------------------------------------------------------------
    // read loop
    //----------------------------------------------------------------------
    init_average();
    fprintf(stdout, "Measuring pl_read() Data  : ");
    for(j = 0; j < MAX_ITERATIONS; j++) {
        fprintf(stdout, "*");
        start_timer();
        for(i = 0; i < MAX_OPERATIONS; i++) {
            pl_read(pld, &x, 0);
        }
        stop_timer();
        sum_average();
    }
    print_timer();
    fprintf(stdout, "\n");
    compute_average(MAX_ITERATIONS * MAX_OPERATIONS);
    pl_read_average_cycles = average_counter;

    //-- end test zone -----------------------------------------------------

    //----------------------------------------------------------------------
    // close test PL
    //----------------------------------------------------------------------
    fprintf(stdout, "Closing Test PL.\n");
    ret = pl_close(pld);
    assert(ret == PL_SUCCESS);

    //----------------------------------------------------------------------
    // report test results
    //----------------------------------------------------------------------
    fprintf(stdout, "\n");
    fprintf(stdout, "Test Report:\n");
    fprintf(stdout, "=============\n");
    fprintf(stdout, "\n");
#ifdef __PL_WINDOWS__
    fprintf(stdout, "Average CPU cycles per pl_write() call :       %12I64u.\n", pl_write_average_cycles);
    fprintf(stdout, "Average CPU cycles per pl_read() call  :       %12I64u.\n", pl_read_average_cycles);
#endif // __PL_WINDOWS__
#if defined (__PL_LINUX__) || (__PL_SOLARIS__) || (__PL_MACOSX__)
    fprintf(stdout, "Average CPU cycles per pl_write() call :       %12llu.\n", pl_write_average_cycles);
    fprintf(stdout, "Average CPU cycles per pl_read() call  :       %12llu.\n", pl_read_average_cycles);
#endif // __PL_LINUX__ || __PL_SOLARIS__ || __PL_MACOSX__
    fprintf(stdout, "\n");
    fprintf(stdout, "Notes:\n");
    fprintf(stdout, "======\n");
    fprintf(stdout, " *  A 2.0 GHz processor with two cores processes ~4 billion\n");
    fprintf(stdout, "instructions per second (~2 billion per core).   Allocation\n");
    fprintf(stdout, "of system CPU cycles under the following conditions:\n");
#ifdef __PL_WINDOWS__
    fprintf(stdout, "1000 pl_write() calls per second:                   ~%1.3f%%\n", (double)pl_write_average_cycles / 40000.0);
    fprintf(stdout, "1000 pl_read() calls per second:                    ~%1.3f%%\n", (double)pl_read_average_cycles / 40000.0);
#endif // __PL_WINDOWS__
#if defined (__PL_LINUX__) || (__PL_SOLARIS__) || (__PL_MACOSX__)
    fprintf(stdout, "1000 pl_write() calls per second:                   ~%1.3f%%\n", (double)pl_write_average_cycles / 40000.0);
    fprintf(stdout, "1000 pl_read() calls per second:                    ~%1.3f%%\n", (double)pl_read_average_cycles / 40000.0);
#endif // __PL_LINUX__ || __PL_SOLARIS__ || __PL_MACOSX__	fprintf(stdout, "\n");
    fprintf(stdout, "\n");
    fprintf(stdout, " *  1.0 GHz cycle = 1.0 nanosecond = 1.0 x 10-9 second.\n");
    fprintf(stdout, "                10 nanoseconds   =   1.0 x 10-5 millisecond.\n");
    fprintf(stdout, "               100 nanoseconds   =       0.0001 millisecond.\n");
    fprintf(stdout, "             1,000 nanoseconds   =        0.001 millisecond.\n");
    fprintf(stdout, "            10,000 nanoseconds   =         0.01 millisecond.\n");
    fprintf(stdout, "          100,000 nanoseconds    =          0.1 millisecond.\n");
    fprintf(stdout, "        1,000,000 nanoseconds    =            1 millisecond.\n");
    fprintf(stdout, "\n");
    fprintf(stdout, "************************************************************\n");
    fprintf(stdout, "*               End of micro-benchmark                     *\n");
    fprintf(stdout, "************************************************************\n");
    fprintf(stdout, "\n");

    return(PL_SUCCESS);
}
/*---------------------------------------------------------------------------
Function: main
Purpose : statistic collector entry point
In      : none
Out     : none
Return  : status

History
----------------------------------------------------------------------------
Date        : Author                  Modification
----------------------------------------------------------------------------
07/08/2009    Jamel Tayeb             Creation.
*/
int main(void) {

	int f_load = 0;
	int f_cpu = 0;
	int bret = -1;
	ssize_t sret = 0;
	char separators_load[] = " /\t\n";
	char separators_cpu[] = " \t\n";
	char buffer[BUFFER_SIZE] = { '\0' };
	char *token = NULL;
	unsigned long long value = 0;

	struct sigaction sa;

	char *startup[STARTUP_MESSAGE_LINES_COUNT] = { STARTUP_MESSAGE_LINES };
	unsigned long long samples = 0;
	int chars_displayed = 0;
	int i = 0;

	unsigned long long user_last = 0;
	unsigned long long nice_last = 0;
	unsigned long long system_last = 0;
	unsigned long long idle_last = 0;
	unsigned long long io_wait_last = 0;
	unsigned long long soft_irq_last = 0;
	unsigned long long hard_irq_last = 0;
	unsigned long long steal_last = 0;
	unsigned long long user = 0;
	unsigned long long nice = 0;
	unsigned long long system = 0;
	unsigned long long idle = 0;
	unsigned long long io_wait = 0;
	unsigned long long soft_irq = 0;
	unsigned long long hard_irq = 0;
	unsigned long long steal = 0;

	unsigned long long usage_percentage = 0;
	long double usage_time = 0;
	long double total_time = 0;

	PL_STATUS ret = PL_FAILURE;
	int pld = PL_INVALID_DESCRIPTOR;
	uuid_t uuid;
	char application_name[] = APPLICATION_NAME;

	const char *counters_names[COUNTERS_COUNT] = { 
		CPU_USAGE_COUNTERS, 
		LOAD_COUNTERS, 
		CPU_COUNTERS, 
	};

	enum counters_indexes { 
		CPU_USAGE_PERCENTAGE_INDEX = 0, 
		CPU_USAGE_PERCENTAGE_DECIMALS_INDEX,

		CPU_AND_IO_UTILIZATION_OF_THE_LAST_MINUTE_PERIOD_INDEX, 
		CPU_AND_IO_UTILIZATION_OF_THE_LAST_MINUTE_PERIOD_DECIMALS_INDEX,
		CPU_AND_IO_UTILIZATION_OF_THE_LAST_FIVE_MINUTES_PERIOD_INDEX, 
		CPU_AND_IO_UTILIZATION_OF_THE_LAST_FIVE_MINUTES_PERIOD_DECIMALS_INDEX, 
		CPU_AND_IO_UTILIZATION_OF_THE_LAST_TEN_MINUTES_PERIOD_INDEX, 
		CPU_AND_IO_UTILIZATION_OF_THE_LAST_TEN_MINUTES_PERIOD_DECIMALS_INDEX,
		NUMBER_OF_CURRENTLY_RUNNING_PROCESSES_INDEX, 
		TOTAL_NUMBER_OF_PROCESSES_INDEX, 
		LAST_PROCESS_ID_USED_INDEX,
		
		JIFFIES_IN_USER_MODE_INDEX,
		JIFFIES_IN_LOW_PRIORITY_USER_MODE_INDEX, 
		JIFFIES_IN_SYSTEM_MODE_MODE_INDEX,
		JIFFIES_IN_IDLE_TASK_MODE_INDEX, 
		JIFFIES_IN_IO_WAIT_INDEX, 
		JIFFIES_IN_HARDIRQ_INDEX,
		JIFFIES_IN_SOFTIRQ_INDEX, 
		JIFFIES_IN_STEAL_INDEX
	};

	//------------------------------------------------------------------------
	// print startup message to stdout
	//------------------------------------------------------------------------
	for(i = 0; i < STARTUP_MESSAGE_LINES_COUNT; i++) {
		fprintf(stdout, "%s", startup[i]);
	}

	//------------------------------------------------------------------------
	// instal signal handler
	//------------------------------------------------------------------------
	sa.sa_handler = signal_handler;
	sigemptyset(&sa.sa_mask);	
	sa.sa_flags = 0;
	bret = sigaction(SIGINT, &sa, NULL);
	assert(bret != -1);

	//------------------------------------------------------------------------
	// open PL
	//------------------------------------------------------------------------
	pld = pl_open(application_name, COUNTERS_COUNT, counters_names, &uuid);
	assert(pld != PL_INVALID_DESCRIPTOR);

	//------------------------------------------------------------------------
	// print PL and use message to stdout
	//------------------------------------------------------------------------
	memset(buffer, 0, sizeof(buffer));
	uuid_unparse(uuid, buffer);
	fprintf(stdout, "Using PL.........: [%s]\n", buffer);
	fprintf(stdout, "Exporting........:\n");
	for(i = 0; i < COUNTERS_COUNT; i++) {
		fprintf(stdout, ".................: [%s]\n", counters_names[i]);
	}
	fprintf(stdout, "To Stop Logging  : [<CRTL>+<C>]\n");

	//------------------------------------------------------------------------
	// write static PL counters
	//------------------------------------------------------------------------
	value = 2;
	ret = pl_write(pld, &value, CPU_USAGE_PERCENTAGE_DECIMALS_INDEX); ASSERT;
	ret = pl_write(pld, &value, CPU_AND_IO_UTILIZATION_OF_THE_LAST_MINUTE_PERIOD_DECIMALS_INDEX); ASSERT;
	ret = pl_write(pld, &value, CPU_AND_IO_UTILIZATION_OF_THE_LAST_FIVE_MINUTES_PERIOD_DECIMALS_INDEX); ASSERT;
	ret = pl_write(pld, &value, CPU_AND_IO_UTILIZATION_OF_THE_LAST_TEN_MINUTES_PERIOD_DECIMALS_INDEX); ASSERT;

	//------------------------------------------------------------------------
	// read and export data every second
	//------------------------------------------------------------------------
	while(stop == 0) {

		//--------------------------------------------------------------------
		// start with load data
		//--------------------------------------------------------------------
		f_load = open(DATA_SOURCE_LOAD, O_RDONLY);
		assert(f_load != -1);
		memset(buffer, 0,  BUFFER_SIZE);
		sret = read(f_load, buffer, BUFFER_SIZE);
		assert(sret != -1);
		// last minute load
		token = strtok(buffer, separators_load);
		if(token != NULL) {		
			value = (unsigned long long)(atof(token) * SCALING);
			ret = pl_write(pld, &value, CPU_AND_IO_UTILIZATION_OF_THE_LAST_MINUTE_PERIOD_INDEX); ASSERT;
		}
		// last five minutes load
		token = strtok(NULL, separators_load);
		if(token != NULL) {				
			value = (unsigned long long)(atof(token) * SCALING);
			ret = pl_write(pld, &value, CPU_AND_IO_UTILIZATION_OF_THE_LAST_FIVE_MINUTES_PERIOD_INDEX); ASSERT;
		}
		// last ten minutes load
		token = strtok(NULL, separators_load);
		if(token != NULL) {				
			value = (unsigned long long)(atof(token) * SCALING);
			ret = pl_write(pld, &value, CPU_AND_IO_UTILIZATION_OF_THE_LAST_TEN_MINUTES_PERIOD_INDEX); ASSERT;
		}
		// running processes
		token = strtok(NULL, separators_load);
		if(token != NULL) {				
			value = (unsigned long long)atoi(token);
			ret = pl_write(pld, &value, NUMBER_OF_CURRENTLY_RUNNING_PROCESSES_INDEX); ASSERT;
		}
		// total number of precesses
		token = strtok(NULL, separators_load);
		if(token != NULL) {				
			value = (unsigned long long)atoi(token);
			ret = pl_write(pld, &value, TOTAL_NUMBER_OF_PROCESSES_INDEX); ASSERT;
		}
		// last process id used
		token = strtok(NULL, separators_load);
		if(token != NULL) {				
			value = (unsigned long long)atoi(token);
			ret = pl_write(pld, &value, LAST_PROCESS_ID_USED_INDEX); ASSERT;
		}
		bret = close(f_load);
		assert(bret != -1);

		//--------------------------------------------------------------------
		// continue with cpu data
		//--------------------------------------------------------------------
		f_cpu = open(DATA_SOURCE_CPU, O_RDONLY);
		assert(f_cpu != -1);
		memset(buffer, 0,  BUFFER_SIZE);
		sret = read(f_cpu, buffer, BUFFER_SIZE);
		assert(sret != -1);
		token = strtok(buffer, separators_cpu);
		while(token != NULL) {
			if(strcmp(token, CPU_TO_MONITOR) == 0) {
				// jiffies in user mode
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_USER_MODE_INDEX); ASSERT;
					user_last = user;
					user = value;
				}
				// jiffies in low priority user mode - nice
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_LOW_PRIORITY_USER_MODE_INDEX); ASSERT;
					nice_last = nice;
					nice = value;
				}
				// jiffies in system mode mode
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_SYSTEM_MODE_MODE_INDEX); ASSERT;
					system_last = system;
					system = value;
				}
				// jiffies in idle task mode
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_IDLE_TASK_MODE_INDEX); ASSERT;
					idle_last = idle;
					idle = value;
				}
				// jiffies in IO wait
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_IO_WAIT_INDEX); ASSERT;
					io_wait_last = io_wait;
					io_wait = value;
				}
				// jiffies in IRQ - hardirq
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_HARDIRQ_INDEX); ASSERT;
					hard_irq_last = hard_irq;
					hard_irq = value;
				}
				// jiffies in IRQ - softirq
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_SOFTIRQ_INDEX); ASSERT;
					soft_irq_last = soft_irq;
					soft_irq = value;
				}
				// jiffies in steal
				token = strtok(NULL, separators_cpu);
				if(token != NULL) {				
					value = (unsigned long long)atoi(token);
					ret = pl_write(pld, &value, JIFFIES_IN_STEAL_INDEX); ASSERT;
					steal_last = steal;
					steal = value;
				}
				goto found;
			}
			token = strtok(NULL, separators_cpu);
		}
found:
		bret = close(f_cpu);
		assert(bret != -1);

		//-------------------------------------------------------------------
		// compute cpu utilization %
		//-------------------------------------------------------------------
		usage_time = (long double)(
			(user - user_last) + 
			(nice - nice_last) + 
			(system - system_last) + 
			(soft_irq - soft_irq_last) +
			(hard_irq - hard_irq_last) +
			(steal - steal_last)
		);
		total_time = (long double)(
			usage_time + 
			(idle - idle_last) +
			(io_wait - io_wait_last)
		);
		usage_percentage = (unsigned long long)(100.0 * usage_time / total_time) * 100;
		ret = pl_write(pld, &usage_percentage, CPU_USAGE_PERCENTAGE_INDEX); ASSERT;

		//-------------------------------------------------------------------
		// increment sample(s) count
		//-------------------------------------------------------------------
		samples++;

		//-------------------------------------------------------------------
		// print to stdout the sample count
		//-------------------------------------------------------------------
		chars_displayed = fprintf(stdout, "Samples          : [%llu]", samples);
		fflush(stdout);
		for(i = 0; i < chars_displayed; i++) { fprintf(stdout, "\b"); }

		//-------------------------------------------------------------------
		// sleep for a second
		//-------------------------------------------------------------------
		sleep(1);
	}

	//------------------------------------------------------------------------
	// close PL
	//------------------------------------------------------------------------
	ret = pl_close(pld); ASSERT;
	return(PL_SUCCESS);
}