"Fossies" - the Fresh Open Source Software Archive

Member "bonnie++-2.00a/bon_io.cpp" (13 Sep 2018, 8372 Bytes) of package /linux/privat/bonnie++-2.00a.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 last Fossies "Diffs" side-by-side code changes report: 1.03e_vs_1.04.

    1 #include "bonnie.h"
    2 #include <stdlib.h>
    3 #include <fcntl.h>
    4 
    5 #include <dirent.h>
    6 #include <unistd.h>
    7 #include <sys/wait.h>
    8 #include "sync.h"
    9 
   10 #include <string.h>
   11 #include <limits.h>
   12 
   13 #include "bon_io.h"
   14 #include "bon_time.h"
   15 
   16 
   17 #define END_SEEK_PROCESS INT_MIN
   18 
   19 CFileOp::~CFileOp()
   20 {
   21   Close();
   22   if(m_name)
   23   {
   24     unlink(m_name);
   25     free(m_name);
   26   }
   27   delete m_buf;
   28 }
   29 
   30 Thread *CFileOp::newThread(int threadNum)
   31 {
   32   return new CFileOp(threadNum, this);
   33 }
   34 
   35 CFileOp::CFileOp(int threadNum, CFileOp *parent)
   36  : Thread(threadNum, parent)
   37  , m_timer(parent->m_timer)
   38  , m_file_size(parent->m_file_size)
   39  , m_fd(-1)
   40  , m_isopen(false)
   41  , m_name(PCHAR(malloc(strlen(parent->m_name) + 5)))
   42  , m_sync(parent->m_sync)
   43 #ifdef O_DIRECT
   44  , m_use_direct_io(parent->m_use_direct_io)
   45 #endif
   46  , m_chunk_bits(parent->m_chunk_bits)
   47  , m_chunk_size(parent->m_chunk_size)
   48  , m_total_chunks(parent->m_total_chunks)
   49  , m_buf(new char[m_chunk_size])
   50 {
   51   strcpy(m_name, parent->m_name);
   52 }
   53 
   54 int CFileOp::action(PVOID)
   55 {
   56   struct report_s seeker_report;
   57   if(reopen(false))
   58     return 1;
   59   int ticket;
   60   int rc;
   61   Duration dur, test_time;
   62   rc = Read(&ticket, sizeof(ticket), 0);
   63   CPU_Duration test_cpu;
   64   test_time.getTime(&seeker_report.StartTime);
   65   test_cpu.start();
   66   if(rc == sizeof(ticket) && ticket != END_SEEK_PROCESS) do
   67   {
   68     bool update = false;
   69     if(ticket < 0)
   70     {
   71       ticket = abs(ticket);
   72       update = true;
   73     }
   74     dur.start();
   75     if(doseek(ticket % m_total_chunks, update) )
   76       return 1;
   77     dur.stop();
   78   } while((rc = Read(&ticket, sizeof(ticket), 0)) == sizeof(ticket)
   79          && ticket != END_SEEK_PROCESS);
   80 
   81   if(rc != sizeof(ticket))
   82   {
   83     fprintf(stderr, "Can't read ticket.\n");
   84     return 1;
   85   }
   86   Close();
   87   // seeker report is start and end times, CPU used, and latency
   88   test_time.getTime(&seeker_report.EndTime);
   89   seeker_report.CPU = test_cpu.stop();
   90   seeker_report.Latency = dur.getMax();
   91   if(Write(&seeker_report, sizeof(seeker_report), 0) != sizeof(seeker_report))
   92   {
   93     fprintf(stderr, "Can't write report.\n");
   94     return 1;
   95   }
   96   return 0;
   97 }
   98 
   99 int CFileOp::seek_test(Rand &r, bool quiet, int Seeks, int SeekProcCount, Sync &s)
  100 {
  101   int message_count = SeekProcCount + Seeks;
  102   int *seek_tickets = (int *)malloc(sizeof(int) * message_count);
  103   int next;
  104   for(next = 0; next < Seeks; next++)
  105   {
  106     seek_tickets[next] = r.getNum();
  107     if(seek_tickets[next] < 0)
  108       seek_tickets[next] = abs(seek_tickets[next]);
  109     if(seek_tickets[next] % UpdateSeek == 0)
  110       seek_tickets[next] = -seek_tickets[next];
  111   }
  112   for( ; next < (Seeks + SeekProcCount); next++)
  113     seek_tickets[next] = END_SEEK_PROCESS;
  114   if(reopen(false))
  115     return 1;
  116   go(NULL, SeekProcCount);
  117 
  118   sleep(3);
  119   if(s.decrement_and_wait(Lseek))
  120     return 1;
  121   if(!quiet) fprintf(stderr, "start 'em...");
  122   if(Write(seek_tickets, sizeof(int) * message_count, 0) != (int)sizeof(int) * message_count)
  123   {
  124     fprintf(stderr, "Can't write tickets.\n");
  125     return 1;
  126   }
  127   Close();
  128   for (next = 0; next < SeekProcCount; next++)
  129   { /* for each child */
  130     struct report_s seeker_report;
  131 
  132     int rc;
  133     if((rc = Read(&seeker_report, sizeof(seeker_report), 0))
  134         != sizeof(seeker_report))
  135     {
  136       fprintf(stderr, "Can't read from pipe, expected %d, got %d.\n"
  137                     , int(sizeof(seeker_report)), rc);
  138       return 1;
  139     }
  140 
  141     /*
  142      * each child writes back its CPU, start & end times.  The elapsed time
  143      *  to do all the seeks is the time the first child started until the
  144      *  time the last child stopped
  145      */
  146     m_timer.add_delta_report(seeker_report, Lseek);
  147     if(!quiet) fprintf(stderr, "done...");
  148   } /* for each child */
  149   if(!quiet) fprintf(stderr, "\n");
  150   return 0;
  151 }
  152 
  153 int CFileOp::seek(int offset, int whence)
  154 {
  155   OFF_TYPE rc;
  156   OFF_TYPE real_offset = offset;
  157   real_offset *= m_chunk_size;
  158   rc = file_lseek(m_fd, real_offset, whence);
  159 
  160   if(rc == OFF_TYPE(-1))
  161   {
  162     sprintf(m_buf, "Error in lseek to chunk %d(" OFF_T_PRINTF ")", offset, real_offset);
  163     perror(m_buf);
  164     return rc;
  165   }
  166   return 0;
  167 }
  168 
  169 int CFileOp::read_block(PVOID buf)
  170 {
  171   int total = 0;
  172   bool printed_error = false;
  173   while(total != m_chunk_size)
  174   {
  175     int rc = read(m_fd, buf, m_chunk_size - total);
  176     if(rc == -1)
  177     {
  178       io_error("re-write read"); // exits program
  179     }
  180     else if(rc != m_chunk_size)
  181     {
  182       if(!printed_error)
  183       {
  184         fprintf(stderr, "Can't read a full block, only got %d bytes.\n", rc);
  185         printed_error = true;
  186         if(rc == 0)
  187           return -1;
  188       }
  189     }
  190     total += rc;
  191   }
  192   return total;
  193 }
  194 
  195 int CFileOp::read_block_byte(char *buf)
  196 {
  197   char next;
  198   for(int i = 0; i < m_chunk_size; i++)
  199   {
  200     if(read(m_fd, &next, 1) != 1)
  201     {
  202       fprintf(stderr, "Can't read a byte\n");
  203       return -1;
  204     }
  205     /* just to fool optimizers */
  206     buf[int(next)]++;
  207   }
  208 
  209   return 0;
  210 }
  211 
  212 int CFileOp::write_block(PVOID buf)
  213 {
  214   int rc = ::write(m_fd, buf, m_chunk_size);
  215   if(rc != m_chunk_size)
  216   {
  217     perror("Can't write block.");
  218     return -1;
  219   }
  220   return rc;
  221 }
  222 
  223 int CFileOp::write_block_byte()
  224 {
  225   for(int i = 0; i < m_chunk_size; i++)
  226   {
  227     char c = i & 0x7f;
  228     if(write(m_fd, &c, 1) != 1)
  229     {
  230       fprintf(stderr, "Can't write() - disk full?\n");
  231       return -1;
  232     }
  233   }
  234   return 0;
  235 }
  236 
  237 int CFileOp::Open(CPCCHAR base_name, bool create)
  238 {
  239   m_name = PCHAR(malloc(strlen(base_name) + 5));
  240   strcpy(m_name, base_name);
  241   return reopen(create);
  242 }
  243 
  244 CFileOp::CFileOp(BonTimer &timer, int file_size, int chunk_bits, bool use_sync
  245 #ifdef O_DIRECT
  246                , bool use_direct_io
  247 #endif
  248                 )
  249  : m_timer(timer)
  250  , m_file_size(file_size)
  251  , m_fd(-1)
  252  , m_isopen(false)
  253  , m_name(NULL)
  254  , m_sync(use_sync)
  255 #ifdef O_DIRECT
  256  , m_use_direct_io(use_direct_io)
  257 #endif
  258  , m_chunk_bits(chunk_bits)
  259  , m_chunk_size(1 << m_chunk_bits)
  260  , m_total_chunks(Unit / m_chunk_size * file_size)
  261  , m_buf(new char[m_chunk_size])
  262 {
  263   if(m_total_chunks / file_size * m_chunk_size != Unit)
  264   {
  265     fprintf(stderr, "File size %d too big for chunk size %d\n", file_size, m_chunk_size);
  266     exit(1);
  267   }
  268 }
  269 
  270 int CFileOp::reopen(bool create)
  271 {
  272   if(m_isopen) Close();
  273 
  274   m_isopen = true;
  275   if(m_open(m_name, create))
  276     return 1;
  277   return 0;
  278 }
  279 
  280 int CFileOp::m_open(CPCCHAR base_name, bool create)
  281 {
  282   int flags;
  283   if(create)
  284   { /* create from scratch */
  285     unlink(base_name);
  286     flags = O_RDWR | O_CREAT | O_EXCL;
  287 #ifdef O_DIRECT
  288     if(m_use_direct_io)
  289       flags |= O_DIRECT;
  290 #endif
  291   }
  292   else
  293   {
  294     flags = O_RDWR;
  295 #ifdef _LARGEFILE64_SOURCE
  296     flags |= O_LARGEFILE;
  297 #endif
  298   }
  299   m_fd = file_open(base_name, flags, S_IRUSR | S_IWUSR);
  300 
  301   if(m_fd == -1)
  302   {
  303     fprintf(stderr, "Can't open file %s\n", base_name);
  304     return -1;
  305   }
  306   return 0;
  307 }
  308 
  309 void CFileOp::Close()
  310 {
  311   if(!m_isopen)
  312     return;
  313   if(m_fd != -1)
  314   {
  315     if(fsync(m_fd))
  316       fprintf(stderr, "Can't sync file.\n");
  317     close(m_fd);
  318   }
  319   m_isopen = false;
  320   m_fd = -1;
  321 }
  322 
  323 
  324 /*
  325  * Do a typical-of-something random I/O.  Any serious application that
  326  *  has a random I/O bottleneck is going to be smart enough to operate
  327  *  in a page mode, and not stupidly pull individual words out at
  328  *  odd offsets.  To keep the cache from getting too clever, some
  329  *  pages must be updated.  However an application that updated each of
  330  *  many random pages that it looked at is hard to imagine.
  331  * However, it would be wrong to put the update percentage in as a
  332  *  parameter - the effect is too nonlinear.  Need a profile
  333  *  of what Oracle or Ingres or some such actually does.
  334  * Be warned - there is a *sharp* elbow in this curve - on a 1-MiB file,
  335  *  most substantial unix systems show >2000 random I/Os per second -
  336  *  obviously they've cached the whole thing and are just doing buffer
  337  *  copies.
  338  */
  339 int
  340 CFileOp::doseek(unsigned int where, bool update)
  341 {
  342   if (seek(where, SEEK_SET) == -1)
  343     return -1;
  344   if (read_block(PVOID(m_buf)) == -1)
  345     return -1;
  346 
  347   /* every so often, update a block */
  348   if (update)
  349   { /* update this block */
  350 
  351     /* touch a byte */
  352     m_buf[where % m_chunk_size]--;
  353     if(seek(where, SEEK_SET) == -1)
  354       return io_error("lseek in doseek update");
  355     if (write_block(PVOID(m_buf)) == -1)
  356       return -1;
  357     if(m_sync)
  358     {
  359       if(fsync(m_fd))
  360       {
  361         fprintf(stderr, "Can't sync file.\n");
  362         return -1;
  363       }
  364     }
  365   } /* update this block */
  366   return 0;
  367 }
  368