"Fossies" - the Fresh Open Source Software Archive

Member "bonnie++-1.04/bon_io.cpp" (4 Sep 2017, 11296 Bytes) of package /linux/privat/bonnie++_1.04.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bon_io.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.03e_vs_1.04.

    1 #ifdef OS2
    2 #define INCL_DOSPROCESS
    3 #define INCL_DOSFILEMGR
    4 #include <os2.h>
    5 #else
    6 #include <dirent.h>
    7 #include <unistd.h>
    8 #include <sys/wait.h>
    9 #endif
   10 #include <stdlib.h>
   11 #include <string.h>
   12 
   13 #include "bonnie.h"
   14 #include "bon_io.h"
   15 #include "semaphore.h"
   16 #include "bon_time.h"
   17 
   18 #include "forkit.h"
   19 
   20 CFileOp::~CFileOp()
   21 {
   22   close();
   23   if(m_name)
   24   {
   25     int len = strlen(m_name);
   26     for(int i = 0; i < m_num_files; i++)
   27     {
   28       sprintf(&m_name[len], ".%03d", i);
   29       unlink(m_name);
   30     }
   31     delete m_name;
   32   }
   33   delete m_buf;
   34 }
   35 
   36 void seeker(Fork *f, PVOID param, int)
   37 {
   38   struct report_s seeker_report;
   39   CFileOp *file = (CFileOp *)param;
   40   int num_chunks = file->chunks();
   41   if(file->reopen(false))
   42     exit(1);
   43   char ticket;
   44   int rc;
   45   int lseek_count = 0;
   46 
   47   rc = f->Read(&ticket, 1, 0);
   48 
   49   file->getTimer().timestamp();
   50   seeker_report.StartTime = file->getTimer().get_cur_time();
   51 
   52   if(rc == 1 && ticket) do
   53   {
   54     bool update;
   55     if( (lseek_count++ % UpdateSeek) == 0)
   56       update = true;
   57     else
   58       update = false;
   59     if(file->doseek(rand() % num_chunks, update) )
   60       exit(1);
   61   }
   62   while((rc = f->Read(&ticket, 1, 0)) == 1 && ticket);
   63 
   64   if(rc != 1)
   65   {
   66     fprintf(stderr, "Can't read ticket.\n");
   67     exit(1);
   68   }
   69   file->close();
   70   file->getTimer().get_delta_report(seeker_report);
   71   if(f->Write(&seeker_report, sizeof(seeker_report)) != sizeof(seeker_report))
   72   {
   73     fprintf(stderr, "Can't write report.\n");
   74     exit(1);
   75   }
   76 }
   77 
   78 int CFileOp::seek_test(bool quiet, Semaphore &s)
   79 {
   80   char   seek_tickets[SeekProcCount + Seeks];
   81   int next;
   82   for (next = 0; next < Seeks; next++)
   83     seek_tickets[next] = 1;
   84   for ( ; next < (Seeks + SeekProcCount); next++)
   85     seek_tickets[next] = 0;
   86   Fork f;
   87   f.go(seeker, this, SeekProcCount);
   88 
   89   sleep(5);
   90   if(s.decrement_and_wait(Lseek))
   91     return 1;
   92   if(!quiet) fprintf(stderr, "start 'em...");
   93   if(f.Write(seek_tickets, sizeof(seek_tickets)) != int(sizeof(seek_tickets)) )
   94   {
   95     fprintf(stderr, "Can't write tickets.\n");
   96     return 1;
   97   }
   98   for (next = 0; next < SeekProcCount; next++)
   99   { /* for each child */
  100     struct report_s seeker_report;
  101 
  102     int rc;
  103     if((rc = f.Read(&seeker_report, sizeof(seeker_report), 0))
  104         != sizeof(seeker_report))
  105     {
  106       fprintf(stderr, "Can't read from pipe, expected %d, got %d.\n"
  107                     , int(sizeof(seeker_report)), rc);
  108       return 1;
  109     }
  110 
  111     /*
  112      * each child writes back its CPU, start & end times.  The elapsed time
  113      *  to do all the seeks is the time the first child started until the
  114      *  time the last child stopped
  115      */
  116     m_timer.add_delta_report(seeker_report, Lseek);
  117 #ifdef OS2
  118     TID status = 0;
  119     if(DosWaitThread(&status, DCWW_WAIT))
  120 #else
  121     int status = 0;
  122     if(wait(&status) == -1)
  123 #endif
  124       return io_error("wait");
  125     if(!quiet) fprintf(stderr, "done...");
  126   } /* for each child */
  127   if(!quiet) fprintf(stderr, "\n");
  128   return 0;
  129 }
  130 
  131 int CFileOp::seek(int offset, int whence)
  132 {
  133   switch(whence)
  134   {
  135     case SEEK_SET:
  136       m_file_ind = offset / m_chunks_per_file;
  137       m_cur_pos = offset % m_chunks_per_file;
  138     break;
  139     case SEEK_CUR:
  140       m_cur_pos += offset;
  141       while(m_cur_pos < 0)
  142       {
  143         m_file_ind--;
  144         m_cur_pos += m_chunks_per_file;
  145       }
  146       while(m_cur_pos >= m_chunks_per_file)
  147       {
  148         m_file_ind++;
  149         m_cur_pos -= m_chunks_per_file;
  150       }
  151     break;
  152     default:
  153       fprintf(stderr, "unsupported seek option\n");
  154       return -1;
  155   }
  156   if(m_file_ind == m_num_files)
  157   {
  158     m_file_ind--;
  159     m_cur_pos += m_chunks_per_file;
  160   }
  161   else
  162   {
  163     if(m_file_ind < 0 || m_file_ind >= m_num_files
  164        || (m_file_ind == m_num_files - 1 && m_cur_pos >= m_last_file_chunks))
  165     {
  166       fprintf(stderr, "Bad seek offset\n");
  167       return -1;
  168     }
  169     off_t rc;
  170     if(m_fd)
  171     {
  172 #ifdef OS2
  173       unsigned long actual;
  174       rc = DosSetFilePtr(m_fd[m_file_ind], m_cur_pos << m_chunk_bits, FILE_BEGIN, &actual);
  175       if(rc != 0) rc = -1;
  176 #else
  177       rc = lseek(m_fd[m_file_ind], m_cur_pos << m_chunk_bits, SEEK_SET);
  178 #endif
  179     }
  180     else
  181     {
  182       rc = fseek(m_stream[m_file_ind], m_cur_pos << m_chunk_bits, SEEK_SET);
  183     }
  184 
  185     if(rc == off_t(-1))
  186       fprintf(stderr, "Error in lseek to %d\n", (m_cur_pos << m_chunk_bits));
  187     else
  188       rc = 0;
  189     return rc;
  190   }
  191   return 0;
  192 }
  193 
  194 int CFileOp::read_block(PVOID buf)
  195 {
  196   int total = 0;
  197   bool printed_error = false;
  198   while(total != m_chunk_size)
  199   {
  200 #ifdef OS2
  201     unsigned long actual;
  202     int rc = DosRead(m_fd[m_file_ind], buf, m_chunk_size - total
  203                    , &actual);
  204     if(rc)
  205       rc = -1;
  206     else
  207       rc = actual;
  208 #else
  209     int rc = ::read(m_fd[m_file_ind], buf, m_chunk_size - total);
  210 #endif
  211     m_cur_pos++;
  212     if(m_cur_pos >= m_chunks_per_file)
  213     {
  214       if(seek(0, SEEK_CUR) == -1)
  215       {
  216         fprintf(stderr, "Error in seek(0)\n");
  217         return -1;
  218       }
  219     }
  220     if(rc == -1)
  221     {
  222       io_error("re-write read"); // exits program
  223     }
  224     else if(rc != m_chunk_size && !printed_error)
  225     {
  226       fprintf(stderr, "Can't read a full block, only got %d bytes.\n", rc);
  227       printed_error = true;
  228     }
  229     total += rc;
  230   }
  231   return total;
  232 }
  233 
  234 int CFileOp::read_block_getc(char *buf)
  235 {
  236   int next;
  237   for(int i = 0; i < m_chunk_size; i++)
  238   {
  239     if ((next = getc(m_stream[m_file_ind])) == EOF)
  240     {
  241       fprintf(stderr, "Can't getc(3)\n");
  242       return -1;
  243     }
  244     /* just to fool optimizers */
  245     buf[next]++;
  246   }
  247 
  248   m_cur_pos++;
  249   if(m_cur_pos >= m_chunks_per_file)
  250   {
  251     if(seek(0, SEEK_CUR) == -1)
  252       return -1;
  253   }
  254   return 0;
  255 }
  256 
  257 int CFileOp::write_block(PVOID buf)
  258 {
  259 #ifdef OS2
  260   unsigned long actual;
  261   int rc = DosWrite(m_fd[m_file_ind], buf, m_chunk_size, &actual);
  262   if(rc)
  263     rc = -1;
  264   else
  265     rc = 0;
  266   if(actual != m_chunk_size)
  267     rc = -1;
  268 #else
  269   int rc = ::write(m_fd[m_file_ind], buf, m_chunk_size);
  270   if(rc != m_chunk_size)
  271   {
  272     fprintf(stderr, "Can't write block; rc=%d, buf=%p, chunk_size=%d\n", rc, buf, m_chunk_size);
  273     return -1;
  274   }
  275 #endif
  276   m_cur_pos++;
  277   if(m_cur_pos >= m_chunks_per_file)
  278   {
  279     if(seek(0, SEEK_CUR) == -1)
  280       return -1;
  281   }
  282   return rc;
  283 }
  284 
  285 int CFileOp::write_block_putc()
  286 {
  287   for(int i = 0; i < m_chunk_size; i++)
  288   {
  289     if (putc(i & 0x7f, m_stream[m_file_ind]) == EOF)
  290     {
  291       fprintf(stderr, "Can't putc() - disk full?\n");
  292       return -1;
  293     }
  294   }
  295   m_cur_pos++;
  296   if(m_cur_pos >= m_chunks_per_file)
  297   {
  298     if(seek(0, SEEK_CUR) == -1)
  299       return -1;
  300   }
  301   return 0;
  302 }
  303 
  304 int CFileOp::open(CPCCHAR base_name, bool create, bool use_fopen)
  305 {
  306   m_name = new char[strlen(base_name) + 9];
  307   strcpy(m_name, base_name);
  308   return reopen(create, use_fopen);
  309 }
  310 
  311 CFileOp::CFileOp(BonTimer &timer, int file_size, int chunk_bits, bool use_sync
  312 #ifdef O_DIRECT
  313                , bool use_direct_io
  314 #endif
  315                 )
  316  : m_timer(timer)
  317  , m_stream(NULL)
  318  , m_fd(NULL)
  319  , m_isopen(false)
  320  , m_name(NULL)
  321  , m_sync(use_sync)
  322 #ifdef O_DIRECT
  323  , m_use_direct_io(use_direct_io)
  324 #endif
  325  , m_chunk_bits(chunk_bits)
  326  , m_chunk_size(1 << m_chunk_bits)
  327  , m_chunks_per_file(Unit / m_chunk_size * IOFileSize)
  328  , m_total_chunks(Unit / m_chunk_size * file_size)
  329  , m_last_file_chunks(m_total_chunks % m_chunks_per_file)
  330  , m_cur_pos(0)
  331  , m_file_ind(0)
  332  , m_file_size(file_size)
  333  , m_num_files(m_file_size / IOFileSize + 1)
  334  , m_buf(new char[m_chunk_size])
  335 {
  336   if(m_last_file_chunks == 0)
  337   {
  338     m_last_file_chunks = m_chunks_per_file;
  339     m_num_files--;
  340   }
  341 }
  342 
  343 typedef FILE * PFILE;
  344 
  345 int CFileOp::reopen(bool create, bool use_fopen)
  346 {
  347   int i;
  348   m_cur_pos = 0;
  349   m_file_ind = 0;
  350 
  351   if(m_isopen) close();
  352 
  353   m_isopen = true;
  354   if(use_fopen)
  355   {
  356     m_stream = new PFILE[m_num_files];
  357     for(i = 0; i < m_num_files; i++)
  358       m_stream[i] = NULL;
  359   }
  360   else
  361   {
  362 #ifdef OS2
  363     m_fd = new HFILE[m_num_files];
  364 #else
  365     m_fd = new int[m_num_files];
  366 #endif
  367     for(i = 0; i < m_num_files; i++)
  368       m_fd[i] = -1;
  369   }
  370   int len = strlen(m_name);
  371   for(i = 0; i < m_num_files; i++)
  372   {
  373     sprintf(&m_name[len], ".%04d", i);
  374     if(m_open(m_name, i, create))
  375       return 1;
  376   }
  377   m_name[len] = '\0';
  378   return 0;
  379 }
  380 
  381 int CFileOp::m_open(CPCCHAR base_name, int ind, bool create)
  382 {
  383 #ifdef OS2
  384   ULONG createFlag;
  385 #else
  386   int flags;
  387 #endif
  388   const char *fopen_mode;
  389   if(create)
  390   { /* create from scratch */
  391 #ifndef OS2
  392     unlink(base_name);
  393 #endif
  394     fopen_mode = "w+";
  395 #ifdef OS2
  396     createFlag = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
  397 #else
  398     flags = O_RDWR | O_CREAT | O_EXCL;
  399 #ifdef O_DIRECT
  400     if(m_use_direct_io)
  401     {
  402       flags |= O_DIRECT;
  403     }
  404 #endif
  405 #endif
  406   }
  407   else
  408   {
  409     fopen_mode = "r+";
  410 #ifdef OS2
  411     createFlag = OPEN_ACTION_OPEN_IF_EXISTS;
  412 #else
  413     flags = O_RDWR;
  414 #endif
  415   }
  416   if(m_fd)
  417   {
  418 #ifdef OS2
  419     ULONG action = 0;
  420     ULONG rc = DosOpen(base_name, &m_fd[ind], &action, 0, FILE_NORMAL, createFlag
  421                      , OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE
  422                      , NULL);
  423     if(rc)
  424       m_fd[ind] = -1;
  425 #else
  426     m_fd[ind] = ::open(base_name, flags, S_IRUSR | S_IWUSR);
  427 #endif
  428   }
  429   else
  430   {
  431     m_stream[ind] = fopen(base_name, fopen_mode);
  432   }
  433 
  434   if( (m_fd && m_fd[ind] == -1) || (m_stream && m_stream[ind] == NULL) )
  435   {
  436     fprintf(stderr, "Can't open file %s\n", base_name);
  437     return -1;
  438   }
  439   return 0;
  440 }
  441 
  442 void CFileOp::close()
  443 {
  444   if(!m_isopen)
  445     return;
  446   for(int i = 0; i < m_num_files; i++)
  447   {
  448     if(m_sync)
  449       fflush(NULL);
  450     if(m_stream && m_stream[i]) fclose(m_stream[i]);
  451     if(m_fd && m_fd[i] != -1)
  452     {
  453       if(m_sync)
  454       {
  455         if(fsync(m_fd[i]))
  456           fprintf(stderr, "Can't sync files.\n");
  457       }
  458       file_close(m_fd[i]);
  459     }
  460   }
  461   m_isopen = false;
  462   delete m_fd;
  463   delete m_stream;
  464   m_fd = NULL;
  465   m_stream = NULL;
  466 }
  467 
  468 
  469 /*
  470  * Do a typical-of-something random I/O.  Any serious application that
  471  *  has a random I/O bottleneck is going to be smart enough to operate
  472  *  in a page mode, and not stupidly pull individual words out at
  473  *  odd offsets.  To keep the cache from getting too clever, some
  474  *  pages must be updated.  However an application that updated each of
  475  *  many random pages that it looked at is hard to imagine.
  476  * However, it would be wrong to put the update percentage in as a
  477  *  parameter - the effect is too nonlinear.  Need a profile
  478  *  of what Oracle or Ingres or some such actually does.
  479  * Be warned - there is a *sharp* elbow in this curve - on a 1-MiB file,
  480  *  most substantial unix systems show >2000 random I/Os per second -
  481  *  obviously they've cached the whole thing and are just doing buffer
  482  *  copies.
  483  */
  484 int
  485 CFileOp::doseek(long where, bool update)
  486 {
  487   if (seek(where, SEEK_SET) == -1)
  488     return io_error("lseek in doseek");
  489   if (read_block(PVOID(m_buf)) == -1)
  490     return io_error("read in doseek");
  491 
  492   /* every so often, update a block */
  493   if (update)
  494   { /* update this block */
  495 
  496     /* touch a byte */
  497     m_buf[int(rand()) % m_chunk_size]--;
  498     if(seek(where, SEEK_SET) == -1)
  499       return io_error("lseek in doseek update");
  500     if (write_block(PVOID(m_buf)) == -1)
  501       return io_error("write in doseek");
  502     if(m_sync)
  503     {
  504       if(fsync(m_fd[m_file_ind]))
  505       {
  506         fprintf(stderr, "Can't sync file.\n");
  507         return -1;
  508       }
  509     }
  510   } /* update this block */
  511   return 0;
  512 }
  513