Util.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file Util.cxx
3 /// \brief Utilities for mmap
4 /// \author Christopher Backhouse - bckhouse@caltech.edu
5 ////////////////////////////////////////////////////////////////////////
6 
7 #include "LEM/func/Util.h"
8 
9 #include <sys/file.h>
10 #include <sys/mman.h>
11 #include <sys/stat.h>
12 
13 #include <cassert>
14 #include <iostream>
15 
16 namespace lem
17 {
18  long MMapFileAtAddress(const std::string& fname, void* addr, bool touchAll,
19  const std::string& lockName)
20  {
21  // Touching all the memory ("preloading") means we can be sure that it's
22  // all quickly available to us later. The first process to do this has to
23  // fetch the whole file from disk. We don't want more than one process
24  // doing that, it's counter-productive. But once that's happened once, it's
25  // in disk cache, and all other processes should feel free to preload in
26  // parallel. This locking scheme ensures that.
27 
28  FILE* lockMain = 0;
29  FILE* lockDone = 0;
30  if(touchAll && !lockName.empty()){
31  // No two processes should be preloading from disk at once
32 
33  // Make sure not to block out other users from this lock
34  chmod(lockName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
35  chmod((lockName+".done").c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
36 
37  lockMain = fopen(lockName.c_str(), "w");
38  int ret = flock(fileno(lockMain), LOCK_EX);
39  assert(ret == 0); // Blocking flock call, must have got it
40 
41  // We're now holding the loading lock. Either it's our responsibility to
42  // do the preload, or someone else beat us to it but is now done, so we
43  // can go ahead freely. Check the ".done" lock to see which.
44 
45  lockDone = fopen((lockName+".done").c_str(), "w");
46  ret = flock(fileno(lockDone), LOCK_EX | LOCK_NB);
47  // If we succesfully get this lock, that means that no running processes
48  // have preloaded the file for us.
49  if(ret == 0){
50  // Drop it again, we were just testing
51  fclose(lockDone);
52  lockDone = 0;
53  }
54  else{
55  // Otherwise, someone else has already done the preload. Don't hold the
56  // rest of the processes up.
57  fclose(lockMain);
58  lockMain = 0;
59  }
60  }
61 
62 
63  FILE* f = fopen(fname.c_str(), "r");
64  assert(f);
65 
66  struct stat st;
67  fstat(fileno(f), &st);
68  const long fsize = st.st_size;
69 
70  void* ret = mmap(addr, fsize, PROT_READ, MAP_SHARED | MAP_FIXED, fileno(f), 0);
71  fclose(f);
72  assert(ret != (void*)-1);
73 
74 
75  if(touchAll){
76  // Touch all the memory, one byte on each page
77  char tot = 0;
78  for(long i = 0; i < fsize; i += 4096){
79  if((i/4096)%(fsize/409600) == 0) std::cout << (100*i)/fsize << "%" << std::endl;
80  tot += ((char*)addr)[i];
81  }
82  // Printing forces it not to get optimized out
83  std::cout << "Fully loaded: " << int(tot) << std::endl;
84 
85  if(!lockName.empty()){
86  lockDone = fopen((lockName+".done").c_str(), "w");
87  // Mark that we succesfully preloaded the file. This indication lasts
88  // until the end of this process.
89  flock(fileno(lockDone), LOCK_SH);
90 
91  // Release the main lock if we still have it
92  if(lockMain) fclose(lockMain);
93  }
94  }
95 
96  return fsize;
97  }
98 }
PID
Definition: FillPIDs.h:14
fclose(fg1)
long MMapFileAtAddress(const std::string &fname, void *addr, bool touchAll, const std::string &lockName)
Definition: Util.cxx:18
OStream cout
Definition: OStream.cxx:6
::xsd::cxx::tree::string< char, simple_type > string
Definition: Database.h:154
assert(nhit_max >=nhit_nbins)
unsigned int fileno
Definition: runWimpSim.h:102