PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/simulator/ProtoResultLog.cpp

https://code.google.com/p/voteutil/
C++ | 246 lines | 219 code | 18 blank | 9 comment | 45 complexity | 3332e9427277ad1f644c5f57acdac389 MD5 | raw file
  1. #include "ProtoResultLog.h"
  2. #include <stdio.h>
  3. #include <fcntl.h>
  4. #include <sys/stat.h>
  5. #include "trial.pb.h"
  6. #include <google/protobuf/io/zero_copy_stream_impl.h>
  7. #include <google/protobuf/io/coded_stream.h>
  8. using google::protobuf::uint32;
  9. /* static */
  10. ProtoResultLog* ProtoResultLog::openForAppend(const char* filename) {
  11. int fd = ::open(filename, O_APPEND|O_WRONLY|O_CREAT, 0666);
  12. if (fd < 0) {
  13. perror(filename);
  14. return NULL;
  15. }
  16. ProtoResultLog* out = new ProtoResultLog(strdup(filename), fd);
  17. out->setupForAppend();
  18. return out;
  19. }
  20. ProtoResultLog* ProtoResultLog::openForReading(const char* filename) {
  21. int fd = -1;
  22. ProtoResultLog* out;
  23. if ((filename == NULL) || (!strcmp(filename, "-"))) {
  24. fd = STDIN_FILENO;
  25. filename = "";
  26. } else {
  27. fd = ::open(filename, O_RDONLY);
  28. if (fd < 0) {
  29. perror(filename);
  30. return NULL;
  31. }
  32. }
  33. out = new ProtoResultLog(strdup(filename), fd);
  34. out->setupForRead();
  35. return out;
  36. }
  37. void ProtoResultLog::setupForAppend() {
  38. zcos = new FileOutputStream(fd);
  39. cos = new CodedOutputStream(zcos);
  40. }
  41. void ProtoResultLog::setupForRead() {
  42. zcis = new FileInputStream(fd);
  43. cis = new CodedInputStream(zcis);
  44. cis->SetTotalBytesLimit(1024*1024*1024, 1024*1024*1024);
  45. }
  46. static char* namefilename(const char* fname) {
  47. char* namefname = (char*)malloc(strlen(fname) + 7);
  48. strcpy(namefname, fname);
  49. strcat(namefname, ".names");
  50. return namefname;
  51. }
  52. // protected
  53. ProtoResultLog::ProtoResultLog(char* fname_, int fd_)
  54. : ResultLog(), fname(fname_), fd(fd_),
  55. zcis(NULL), cis(NULL), zcos(NULL), cos(NULL)
  56. {
  57. int err = pthread_mutex_init(&lock, NULL);
  58. assert(err == 0);
  59. {
  60. // load names from file
  61. char* namefname = namefilename(fname);
  62. struct stat s;
  63. err = stat(namefname, &s);
  64. if (err >= 0) {
  65. fprintf(stderr, "loading names from \"%s\" ...", namefname);
  66. int namefd = ::open(namefname, O_RDONLY);
  67. if (namefd >= 0) {
  68. NameBlock* nb = new NameBlock();
  69. char* block = (char*)malloc(s.st_size);
  70. err = read(namefd, block, s.st_size);
  71. assert(err == s.st_size);
  72. //nb->blockLen = err;
  73. //parseNameBlock(nb);
  74. nb->parse(block, s.st_size);
  75. names = nb;
  76. delete_names = true;
  77. close(namefd);
  78. fprintf(stderr, "done.\n");
  79. } else {
  80. perror(namefname);
  81. }
  82. }
  83. free(namefname);
  84. }
  85. }
  86. ProtoResultLog::~ProtoResultLog() {
  87. if (cos != NULL) delete cos;
  88. if (zcos != NULL) delete zcos;
  89. if (cis != NULL) delete cis;
  90. if (zcis != NULL) delete zcis;
  91. if (fd >= 0) {
  92. close(fd);
  93. }
  94. if (fname) {
  95. free(fname);
  96. }
  97. pthread_mutex_destroy(&lock);
  98. }
  99. bool ProtoResultLog::useNames(NameBlock* nb) {
  100. if (names == NULL) {
  101. // use these names, write out to file.
  102. bool ok = true;
  103. char* namefname = namefilename(fname);
  104. fprintf(stderr, "writing out names to \"%s\" ...", namefname);
  105. names = nb;
  106. //makeBlock(nb);
  107. int fdout = ::open(namefname, O_WRONLY|O_CREAT, 0644);
  108. if (fdout < 0) {
  109. perror(namefname);
  110. ok = false;
  111. } else {
  112. int err = write(fdout, nb->block, nb->blockLen);
  113. if (err != nb->blockLen) {
  114. perror("write");
  115. ok = false;
  116. }
  117. close(fdout);
  118. fprintf(stderr, "done\n");
  119. }
  120. free(namefname);
  121. return ok;
  122. } else {
  123. fprintf(stderr, "comparing passed in names to existing\n");
  124. // check that passed in and loaded names are the same
  125. if (names->nnames != nb->nnames) {
  126. fprintf(stderr, "mismatch in names. loaded has %d and new run has %d\n", names->nnames, nb->nnames);
  127. return false;
  128. }
  129. for (int i = 0; i < nb->nnames; ++i) {
  130. if (strcmp(names->names[i], nb->names[i])) {
  131. fprintf(stderr, "mismatch at name %d: old \"%s\" != new \"%s\"\n", i, names->names[i], nb->names[i]);
  132. return false;
  133. }
  134. }
  135. return true;
  136. }
  137. }
  138. inline TrialResult::Model trFromVS(VoterSim::PreferenceMode m) {
  139. switch (m) {
  140. case VoterSim::INDEPENDENT_PREFERENCES:
  141. return TrialResult::INDEPENDENT_PREFERENCES;
  142. case VoterSim::NSPACE_PREFERENCES:
  143. return TrialResult::NSPACE_PREFERENCES;
  144. case VoterSim::NSPACE_GAUSSIAN_PREFERENCES:
  145. return TrialResult::NSPACE_GAUSSIAN_PREFERENCES;
  146. default:
  147. assert(0);
  148. }
  149. return (TrialResult::Model)-1;
  150. }
  151. inline VoterSim::PreferenceMode vsFromTR(TrialResult::Model m) {
  152. switch (m) {
  153. case TrialResult::INDEPENDENT_PREFERENCES:
  154. return VoterSim::INDEPENDENT_PREFERENCES;
  155. case TrialResult::NSPACE_PREFERENCES:
  156. return VoterSim::NSPACE_PREFERENCES;
  157. case TrialResult::NSPACE_GAUSSIAN_PREFERENCES:
  158. return VoterSim::NSPACE_GAUSSIAN_PREFERENCES;
  159. default:
  160. assert(0);
  161. }
  162. return VoterSim::BOGUS_PREFERENCE_MODE;
  163. }
  164. static inline void myperror_(int en, const char* x, const char* file, int line) {
  165. char es[256];
  166. strerror_r(en, es, sizeof(es));
  167. fprintf(stderr, "%s:%d %s: %s\n", file, line, x, es);
  168. }
  169. #define myperror(a,b) myperror_(a, b, __FILE__, __LINE__)
  170. bool ProtoResultLog::logResult(const Result& x) {
  171. TrialResult r;
  172. r.set_voters(x.voters);
  173. r.set_choices(x.choices);
  174. r.set_error(x.error);
  175. if (x.seats != 1) {
  176. r.set_seats(x.seats);
  177. }
  178. r.set_system_index(x.systemIndex);
  179. r.set_voter_model(trFromVS(x.mode));
  180. r.set_dimensions(x.dimensions);
  181. r.set_mean_happiness(x.happiness);
  182. r.set_voter_happiness_stddev(x.voterHappinessStd);
  183. r.set_gini_index(x.gini);
  184. bool ok = true;
  185. #if 0
  186. fprintf(stderr, "%d\t%d\t%f\t%d\t%d\t%d\t%f\t%f\t%f\n",
  187. voters, choices, error, systemIndex, mode, dimensions,
  188. happiness, voterHappinessStd, gini);
  189. #endif
  190. pthread_mutex_lock(&lock);
  191. if (cos != NULL) {
  192. cos->WriteVarint32(r.ByteSize());
  193. ok = r.SerializeToCodedStream(cos);
  194. if (!ok) {
  195. myperror(zcos->GetErrno(), fname);
  196. }
  197. } else {
  198. fprintf(stderr, "output is not setup\n");
  199. ok = false;
  200. }
  201. pthread_mutex_unlock(&lock);
  202. return ok;
  203. }
  204. // return true if a result was read. false implies error or eof.
  205. bool ProtoResultLog::readResult(Result* x) {
  206. TrialResult r;
  207. if (cis == NULL) return false;
  208. uint32 size;
  209. bool ok = cis->ReadVarint32(&size);
  210. if (!ok) return ok;
  211. CodedInputStream::Limit l = cis->PushLimit(size);
  212. ok = r.ParseFromCodedStream(cis);
  213. cis->PopLimit(l);
  214. if (!ok) return ok;
  215. if (ok) {
  216. x->voters = r.voters();
  217. x->choices = r.choices();
  218. x->error = r.error();
  219. x->seats = r.seats();
  220. x->systemIndex = r.system_index();
  221. x->mode = vsFromTR(r.voter_model());
  222. x->dimensions = r.dimensions();
  223. x->happiness = r.mean_happiness();
  224. x->voterHappinessStd = r.voter_happiness_stddev();
  225. x->gini = r.gini_index();
  226. }
  227. return ok;
  228. }