/*
 * sysmark.c
 *
 * It invokes some system calls supported by DIPC to approximately measure 
 * their performance.
 * You should first run 'sysbench' then 'sysmark'.
 *
 * By Kamran Karimi
 */

#include "sysbm.h"

#define MSG_NUM 7

struct test_msg_t
{
 int size;
 int count;
 double snd_time;
 double rcv_time;
} test_msg[MSG_NUM] = {
 {1, 0, 0.0, 0.0}, {10, 0, 0.0, 0.0}, {100, 0, 0.0, 0.0}, {500, 0, 0.0, 0.0},
 {1000, 0, 0.0, 0.0}, {2000, 0, 0.0, 0.0}, {4000, 0, 0.0, 0.0} };

int msg_resultid = -1;


void send_line(char *message)
{
 struct msg_result result_mess; 

 result_mess.mtype = MSG_TYPE;
 strcpy(result_mess.mtext, message);
 if(msg_resultid != -1)
 {
  if(msgsnd(msg_resultid, (struct msgbuf *)&result_mess, MSG_RESULT_SIZE, 0) < 0)
  {
   fprintf(stderr, "sysmark: msgsnd() failed BECAUSE %s\n", strerror(errno));
   exit(20);
  }
 }
 else
  fprintf(stderr, message);  
}


void do_exit(int code)
{
 send_line("done");
 exit(code);
}


void main()
{
 int msgid, semid, shmid;
 int sizeidx, count;
 struct message mess;
 clock_t start, current;
 double ticks_sec, time;
 struct shmid_ds shm_struct;
 struct semid_ds sem_struct;
 struct msqid_ds msg_struct;
 struct sembuf sembuff[2];
 char buff[MSG_RESULT_SIZE];
 
 ticks_sec = (double) sysconf(_SC_CLK_TCK);
 
 msg_resultid = msgget(MSG_RESULT_KEY, MSG_MODE);
 if(msg_resultid < 0)
 {
  sprintf(buff,"sysmark: msgget() failed BECAUSE %s", strerror(errno));
  send_line(buff);
  do_exit(20);
 }
 
 mess.mtype = MSG_TYPE;
 sprintf(buff,"%s", "sysmark: Started. Please Wait...");
 send_line(buff);
 /************************************** 
 printf("sysmark: SEMGET()...\n");*/
 start = times(NULL);
 if((semid = semget(SEM_KEY, 1, SEM_MODE)) < 0)
 {
  sprintf(buff, "sysmark: semget() failed BECAUSE %s", strerror(errno));
  send_line(buff);
  do_exit(20);
 }
 time = (times(NULL) - start) / ticks_sec;
 sprintf(buff, "Executed a semget() operation in %1.2f seconds", time);
 send_line(buff);
 
 /************************************** 
 printf("sysmark: MSGGET()...\n");*/
 start = times(NULL);
 if((msgid = msgget(MSG_KEY, MSG_MODE)) < 0)
 {
  sprintf(buff, "sysmark: msgget() failed BECAUSE %s", strerror(errno));
  send_line(buff);
  do_exit(20);
 }
 time = (times(NULL) - start) / ticks_sec;
 sprintf(buff, "Executed a msgget() operation in %1.2f seconds", time);
 send_line(buff);
 
 /***************************************
 printf("sysmark: SHMGET()...\n");*/
 start = times(NULL);
 if((shmid = shmget(SHM_KEY, SHM_SIZE, MSG_MODE)) < 0)
 {
  sprintf(buff, "sysmark: shmget() failed BECAUSE %s", strerror(errno));
  send_line(buff);
  do_exit(20);
 }
 time = (times(NULL) - start) / ticks_sec;
 sprintf(buff, "Executed a shmget() operation in %1.2f seconds", time);
 send_line(buff);
 
 /***************************************
 printf("sysmark: SEMCTL() with IPC_STAT command...\n"); */
 start = times(NULL);
 count = 0;
 do
 {
  if(semctl(semid, 0, IPC_STAT, &sem_struct) < 0)
  {
   sprintf(buff, "sysmark: semctl() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  count++;
  time = (times(NULL) - start) / ticks_sec; 
 }while(time < 1);
 if(count == 1)
 {
  sprintf(buff, "Executed a semctl() (IPC_STAT) in %1.2f seconds", time);
  send_line(buff);
 } 
 else
 {
  sprintf(buff, "Can execute %1.2f semctl()s (IPC_STAT) in 1 second", count / time);  
  send_line(buff);
 } 
 /***************************************
 printf("sysmark: SEMCTL() with IPC_SET command...\n"); */
 start = times(NULL);
 count = 0;
 do
 {
  if(semctl(semid, 0, IPC_SET, &sem_struct) < 0)
  {
   sprintf(buff, "sysmark: semctl() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  count++;
  time = (times(NULL) - start) / ticks_sec; 
 }while(time < 1);
 if(count == 1)
 {
  sprintf(buff, "Executed a semctl() (IPC_SET) in %1.2f seconds", time);
  send_line(buff);
 } 
 else
 {
  sprintf(buff, "Can execute %1.2f semctl()s (IPC_SET) in 1 second", count / time);  
  send_line(buff);
 } 
  
 /***************************************
 printf("sysmark: MSGCTL() with IPC_STAT command...\n"); */
 start = times(NULL);
 count = 0;
 do
 {
  if(msgctl(msgid, IPC_STAT, &msg_struct) < 0)
  {
   sprintf(buff, "sysmark: msgctl() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  count++;
  time = (times(NULL) - start) / ticks_sec; 
 }while(time < 1);
 if(count == 1)
 {
  sprintf(buff, "Executed a msgctl() (IPC_STAT) in %1.2f seconds", time);
  send_line(buff);
 } 
 else
 {
  sprintf(buff, "Can execute %1.2f msgctl()s (IPC_STAT) in 1 second", count / time);  
  send_line(buff);
 } 
 /***************************************
 printf("sysmark: MSGCTL() with IPC_SET command...\n"); */
 start = times(NULL);
 count = 0;
 do
 {
  if(msgctl(msgid, IPC_SET, &msg_struct) < 0)
  {
   sprintf(buff, "sysmark: msgctl() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  count++;
  time = (times(NULL) - start) / ticks_sec; 
 }while(time < 1);
 if(count == 1)
 {
  sprintf(buff, "Executed a msgctl() (IPC_SET) in %1.2f seconds", time);
  send_line(buff);
 } 
 else
 {
  sprintf(buff, "Can execute %1.2f msgctl()s (IPC_SET) in 1 second", count / time);  
  send_line(buff); 
 } 
 /************************************** 
 printf("sysmark: SHMCTL() with IPC_STAT command\n"); */
 start = times(NULL);
 count = 0;
 do
 {
  if(shmctl(shmid, IPC_STAT, &shm_struct) < 0)
  {
   sprintf(buff, "sysmark: shmctl() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  count++;
  time = (times(NULL) - start) / ticks_sec; 
 }while(time < 1);
 if(count == 1)
 {
  sprintf(buff, "Executed a shmctl() (IPC_STAT) in %1.2f seconds", time);
  send_line(buff);
 } 
 else
 {
  sprintf(buff, "Can execute %1.2f shmctl()s (IPC_STAT) in 1 second", count / time);  
  send_line(buff);
 }
 /************************************** 
 printf("sysmark: SHMCTL() with IPC_SET command\n"); */
 start = times(NULL);
 count = 0;
 do
 {
  if(shmctl(shmid, IPC_SET, &shm_struct) < 0)
  {
   sprintf(buff, "sysmark: shmctl() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  count++;
  time = (times(NULL) - start) / ticks_sec; 
 }while(time < 1);
 if(count == 1)
 {
  sprintf(buff, "Executed a shmctl() (IPC_SET) in %1.2f seconds", time);
  send_line(buff);
 } 
 else
 {
  sprintf(buff, "Can execute %1.2f shmctl()s (IPC_SET) in 1 second", count / time);  
  send_line(buff);
 } 
 /*********************************
 printf("sysmark: MSGSND() and MSGRCV()...\n"); */
 for(sizeidx = 0; sizeidx < MSG_NUM; sizeidx++)
 {
  count = 0;
  do
  {
   start = times(NULL);
   if(msgsnd(msgid, (struct msgbuf *)&mess, test_msg[sizeidx].size, 0) < 0)
   {
    sprintf(buff, "sysmark: msgsnd() failed BECAUSE %s", strerror(errno));
    send_line(buff);
    do_exit(20);
   }
   test_msg[sizeidx].snd_time += (times(NULL) - start) / ticks_sec;
   start = times(NULL);
   if(msgrcv(msgid, (struct msgbuf *)&mess, test_msg[sizeidx].size, 0, 0) < 0)
   {
    sprintf(buff, "sysmark: msgrcv() failed BECAUSE %s", strerror(errno));
    send_line(buff);
    do_exit(20);
   }
   test_msg[sizeidx].rcv_time += (times(NULL) - start) / ticks_sec;
   count++;
  }while(test_msg[sizeidx].rcv_time < 1 && test_msg[sizeidx].snd_time < 1);
  test_msg[sizeidx].count = count;
  if(test_msg[sizeidx].count > 1)
  {
   sprintf(buff, "Can send %1.2f %d byte messages in 1 second",
              test_msg[sizeidx].count / test_msg[sizeidx].snd_time, 
                                              test_msg[sizeidx].size);
   send_line(buff);                                           
   sprintf(buff, "Can receive %1.2f %d byte messages in 1 second",
              test_msg[sizeidx].count / test_msg[sizeidx].rcv_time, 
                                              test_msg[sizeidx].size);                                            
   send_line(buff);
  }
  else
  {
   sprintf(buff, "Sent a %d byte message in %1.2f seconds", 
                          test_msg[sizeidx].size, test_msg[sizeidx].snd_time);
   send_line(buff);                       
   sprintf(buff, "Received a %d byte message in %1.2f seconds", 
                          test_msg[sizeidx].size, test_msg[sizeidx].rcv_time);
   send_line(buff);
  }
 }
 
 /**********************************************
 printf("sysmark: SEMOP()...\n"); */
 sembuff[0].sem_num = 0;
 sembuff[0].sem_op = 1;
 sembuff[0].sem_flg = SEM_UNDO;

 sembuff[1].sem_num = 0;
 sembuff[1].sem_op = -1;
 sembuff[1].sem_flg = SEM_UNDO;
 
 start = times(NULL);
 count = 0;
 do
 {
  if(semop(semid, &sembuff[0], 1) < 0)
  {
   sprintf(buff, "sysmark: semop() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  if(semop(semid, &sembuff[1], 1) < 0)  
  {
   sprintf(buff, "sysmark: semop() failed BECAUSE %s", strerror(errno));
   send_line(buff);
   do_exit(20);
  }
  count++;
  current = times(NULL);
  time = (current - start) / ticks_sec; 
 }while(time < 1);
 if(count == 1)
 {
  sprintf(buff, "Executed a semop() in %1.2f second", time / 2);
  send_line(buff);
 } 
 else
 {
  sprintf(buff, "Can execute %1.2f semop()s in 1 second", count * 2 / time);  
  send_line(buff);
 }  
 /********************************************/
  
 do_exit(0);
}
