PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/tblserver_driver.c

http://audioscout.googlecode.com/
C | 373 lines | 267 code | 65 blank | 41 comment | 24 complexity | f3dff77ce29517b8e8a97b6de2964571 MD5 | raw file
  1. /*
  2. Audio Scout - audio content indexing software
  3. Copyright (C) 2010 D. Grant Starkweather & Evan Klinger
  4. Audio Scout is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. D. Grant Starkweather - dstarkweather@phash.org
  15. Evan Klinger - eklinger@phash.org
  16. */
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <unistd.h>
  20. #include <stdint.h>
  21. #include <pthread.h>
  22. #include <assert.h>
  23. #include <time.h>
  24. #include <math.h>
  25. #include <zmq.h>
  26. #include "zmqhelper.h"
  27. #include "serialize.h"
  28. #include "phash_audio.h"
  29. #include "audiodata.h"
  30. /* simulate this number threads driving tblservd - not actually opening this many threads */
  31. #define NB_THREADS 255
  32. static unsigned int NumberFiles = 0;
  33. /* generates random deviate from poisson distribution around average, lambda */
  34. unsigned int next_arrival(int lambda){
  35. double L = exp(-lambda);
  36. double U, P = 1.0;
  37. unsigned int K = 0;
  38. do {
  39. K++;
  40. U = ((double)rand()+1)/(double)RAND_MAX;
  41. P = P*U;
  42. } while (P > L);
  43. return K-1;
  44. }
  45. /* compute difference in time between timespec's */
  46. struct timespec diff_timespec(struct timespec start, struct timespec end){
  47. struct timespec diff;
  48. if (end.tv_nsec - start.tv_nsec < 0){
  49. diff.tv_sec = end.tv_sec - start.tv_sec - 1;
  50. diff.tv_nsec = 1000000000+end.tv_nsec- start.tv_nsec;
  51. } else {
  52. diff.tv_sec = end.tv_sec - start.tv_sec;
  53. diff.tv_nsec = end.tv_nsec - start.tv_nsec;
  54. }
  55. return diff;
  56. }
  57. typedef struct thr_param_t {
  58. void *ctx;
  59. int port;
  60. }ThrParam;
  61. static const char *query_topic = "phash.q";
  62. static const char *submission_topic = "phash.s";
  63. /* recieve results from table server for the querys */
  64. /* sent from the main thread of this program */
  65. void* result_listener(void *arg){
  66. char addr[32];
  67. ThrParam *thrparam = (ThrParam*)arg;
  68. void *ctx = thrparam->ctx;
  69. int port = thrparam->port;
  70. /* socket to recieve results */
  71. snprintf(addr, 32, "tcp://*:%d", port);
  72. void *skt = socket_bind(ctx, ZMQ_REP, addr);
  73. assert(skt);
  74. /* connect sockets to pipes opened in main */
  75. unsigned int i;
  76. void *rskts[NB_THREADS];
  77. for (i=0;i<NB_THREADS;i++){
  78. snprintf(addr,32, "inproc://timers%d", i);
  79. rskts[i] = socket_connect(ctx, ZMQ_PAIR, addr);
  80. assert(rskts[i]);
  81. }
  82. uint8_t thrdnum;
  83. uint32_t uid, count = 0;
  84. int64_t more;
  85. float cs;
  86. size_t msg_size, more_size = sizeof(int64_t);
  87. void *data;
  88. struct timespec ts, end_ts;
  89. unsigned long long item_start, item_end, start_ul=0ULL, end_ul;
  90. unsigned long long latency, sum = 0ULL, max_latency = 0ULL, min_latency = 9999999ULL;
  91. /* recieves result messages from table server */
  92. /* in multipart message form [ thrdnum | id | cs ] */
  93. do {
  94. /* start recieving a message */
  95. recieve_msg(skt, &msg_size, &more, &more_size, &data);
  96. assert(msg_size == sizeof(uint8_t));
  97. memcpy(&thrdnum, data, sizeof(uint8_t));
  98. free(data);
  99. recieve_msg(skt, &msg_size, &more, &more_size, &data);
  100. assert(msg_size == sizeof(uint32_t));
  101. memcpy(&uid, data, sizeof(uint32_t));
  102. uid = nettohost32(uid);
  103. free(data);
  104. recieve_msg(skt, &msg_size, &more, &more_size, &data);
  105. assert(msg_size == sizeof(float));
  106. memcpy(&cs, data, sizeof(float));
  107. cs = nettohostf(cs);
  108. free(data);
  109. /* respond to table server */
  110. send_empty_msg(skt);
  111. /* recieve the time the query was sent from the respective pipe */
  112. recieve_msg(rskts[thrdnum], &msg_size, &more, &more_size, &data);
  113. assert(msg_size == sizeof(unsigned long long));
  114. memcpy(&item_start, data, sizeof(unsigned long long));
  115. free(data);
  116. /* save start time */
  117. if (count == 0) start_ul = item_start;
  118. /* get time recieved and track some time stats */
  119. clock_gettime(CLOCK_MONOTONIC, &ts);
  120. item_end = 1000000000*ts.tv_sec + ts.tv_nsec;
  121. latency = item_end - item_start;
  122. sum += latency;
  123. if (latency > max_latency) max_latency = latency;
  124. if (latency < min_latency) min_latency = latency;
  125. fprintf(stdout,"-->Recieve(%d) - %u thrd,%u uid,%f cs in %llu nsecs\n",\
  126. count+1, thrdnum,uid,cs, latency);
  127. } while (++count < NumberFiles);
  128. /* get end of time and compute time stats */
  129. clock_gettime(CLOCK_MONOTONIC, &end_ts);
  130. end_ul = 1000000000*end_ts.tv_sec + end_ts.tv_nsec;
  131. unsigned long long total_ul = end_ul - start_ul;
  132. float total_secs = (float)total_ul/1000000000.0f;
  133. float ave_latency = (float)sum/(float)count/1000000000.0f;
  134. float rate = (float)count/total_secs;
  135. float max_latency_f = (float)max_latency/1000000000.0f;
  136. float min_latency_f = (float)min_latency/1000000000.0f;
  137. fprintf(stdout,"Recieved %d query results in %f secs ", count, total_secs);
  138. fprintf(stdout,"at %f querys/sec\n", rate);
  139. fprintf(stdout,"ave latency %f secs\n", ave_latency);
  140. fprintf(stdout,"max latency %f secs\n", max_latency_f);
  141. fprintf(stdout,"min latency %f secs\n", min_latency_f);
  142. for (i=0;i<NB_THREADS;i++){
  143. zmq_close(rskts[i]);
  144. }
  145. zmq_close(skt);
  146. pthread_exit(NULL);
  147. }
  148. int table_listener(void *skt){
  149. fprintf(stdout,"Start/Stop table server now.\n");
  150. uint8_t tblnum = 0;
  151. void *data;
  152. int64_t more;
  153. size_t msg_size, more_size = sizeof(int64_t);
  154. recieve_msg(skt, &msg_size, &more, &more_size, &data);
  155. send_msg_vsm(skt, &tblnum, sizeof(uint8_t));
  156. free(data);
  157. return 0;
  158. }
  159. int get_hashes(const char *dir,unsigned int *nbfiles,uint32_t ***hashes,\
  160. uint32_t **nbframes,const int sr){
  161. char **files = readfilenames(dir, nbfiles);
  162. assert(files);
  163. float *sigbuf = (float*)malloc(1<<26);
  164. assert(sigbuf);
  165. const unsigned int buflen = (1<<26)/sizeof(float);
  166. fprintf(stdout, "\nreading %u files from %s ...\n", *nbfiles, dir);
  167. *hashes = (uint32_t**)malloc(*nbfiles*sizeof(uint32_t*));
  168. assert(hashes);
  169. *nbframes = (uint32_t*)malloc(*nbfiles*sizeof(uint32_t));
  170. assert(nbframes);
  171. AudioHashStInfo hash_st;
  172. uint32_t *hash, nb;
  173. unsigned int i, tmpbuflen;
  174. int err;
  175. for (i=0;i<*nbfiles;i++){
  176. float nbsecs;
  177. do {
  178. nbsecs = (float)(rand()%60);
  179. } while (nbsecs < 30.0f);
  180. tmpbuflen = buflen;
  181. float *buf = readaudio(files[i], sr, sigbuf, &tmpbuflen, nbsecs, NULL, &err);
  182. assert(buf);
  183. audiohash(buf, &hash, NULL, NULL, NULL, &nb, NULL, NULL, tmpbuflen, 0, sr, &hash_st);
  184. (*hashes)[i] = hash;
  185. (*nbframes)[i] = nb;
  186. char *name = strrchr(files[i],'/')+1;
  187. fprintf(stdout,"(%d) %.1f secs of \"%s\"\n", i+1, nbsecs, name);
  188. if (buf != sigbuf) free(buf);
  189. free(files[i]);
  190. }
  191. fprintf(stdout,"\n");
  192. ph_hashst_free(&hash_st);
  193. free(files);
  194. free(sigbuf);
  195. return 0;
  196. }
  197. int main(int argc, char **argv){
  198. if (argc < 4){
  199. fprintf(stdout,"not enough input args\n");
  200. fprintf(stdout,"usage: progname <cmd> <port> <dirname>\n");
  201. fprintf(stdout," cmd - 1 for query mode, 2 for submission mode\n");
  202. fprintf(stdout," port - mock auscoutd port - e.g. 4005\n");
  203. fprintf(stdout," dir - directory of audio files to form queries\n");
  204. return 0;
  205. }
  206. char addr[32];
  207. const int command = (uint8_t)atoi(argv[1]);
  208. const int port = atoi(argv[2]);
  209. const char *dir = argv[3];
  210. const int sr = 6000;
  211. const int table_port = port + 1;
  212. const int result_port = port + 3;
  213. const int pub_port = port + 2;
  214. int arr;
  215. /* seed pseudo-random number generator */
  216. struct timespec seed_ts;
  217. clock_gettime(CLOCK_REALTIME, &seed_ts);
  218. srand(seed_ts.tv_nsec);
  219. uint32_t **hashes = NULL, *nbframes = NULL;
  220. unsigned int nbfiles;
  221. assert(get_hashes(dir, &nbfiles, &hashes, &nbframes, sr)== 0);
  222. assert(hashes);
  223. assert(nbframes);
  224. fprintf(stdout,"\n%u queries from %s\n\n", nbfiles, dir);
  225. NumberFiles = nbfiles;
  226. void *ctx = zmq_init(1);
  227. assert(ctx);
  228. /* port to publish queries */
  229. snprintf(addr, 32, "tcp://*:%d", pub_port);
  230. void *pubskt = socket_bind(ctx, ZMQ_PUB, addr);
  231. assert(pubskt);
  232. sleep(1);
  233. /* inproc sockets to send the times at which the queries are sent to the results thread */
  234. unsigned int i;
  235. void *rskts[NB_THREADS];
  236. for (i=0;i<NB_THREADS;i++){
  237. snprintf(addr, 32, "inproc://timers%d", i);
  238. rskts[i] = socket_bind(ctx, ZMQ_PAIR, addr);
  239. assert(rskts[i]);
  240. }
  241. sleep(1);
  242. /* socket to listen for table server start and stop */
  243. snprintf(addr, 32, "tcp://*:%d", table_port);
  244. void *tblskt = socket_bind(ctx, ZMQ_REP, addr);
  245. assert(tblskt);
  246. sleep(1);
  247. char retchar;
  248. fprintf(stdout,"\nEnter average inter-arrival time in milliseconds:");
  249. scanf("%d%c", &arr, &retchar);
  250. fprintf(stdout,"\nsimulate with %d ms inter-arrival time\n\n", arr);
  251. table_listener(tblskt);
  252. sleep(1);
  253. ThrParam resparam;
  254. resparam.ctx = ctx;
  255. resparam.port = result_port;
  256. pthread_t res_thr;
  257. assert(pthread_create(&res_thr, NULL, result_listener, &resparam) == 0);
  258. sleep(1);
  259. int pause = 0;
  260. uint8_t thrdnum, cmd = command;
  261. uint32_t uid = 0;
  262. struct timespec ts, start_ts, end_ts, diff_ts;
  263. unsigned long long start_ul;
  264. clock_gettime(CLOCK_MONOTONIC, &start_ts);
  265. for (i=0;i<nbfiles;i++){
  266. char *topic = (cmd == 1) ? strdup(query_topic) : strdup(submission_topic);
  267. clock_gettime(CLOCK_MONOTONIC, &ts);
  268. start_ul = 1000000000*ts.tv_sec + ts.tv_nsec;
  269. send_msg_vsm(rskts[thrdnum], &start_ul, sizeof(unsigned long long));
  270. sendmore_msg_data(pubskt, topic, strlen(topic), free_fn, NULL);
  271. sendmore_msg_vsm(pubskt, &cmd, sizeof(uint8_t));
  272. uint32_t snbframes = hosttonet32(nbframes[i]);
  273. sendmore_msg_vsm(pubskt, &snbframes, sizeof(uint32_t));
  274. sendmore_msg_data(pubskt, hashes[i], nbframes[i]*sizeof(uint32_t), NULL, NULL);
  275. sendmore_msg_vsm(pubskt, &thrdnum, sizeof(uint8_t));
  276. uint32_t suid = hosttonet32(uid);
  277. send_msg_vsm(pubskt, &suid, sizeof(uint32_t));
  278. fprintf(stdout,"send(%d) %u thrd, %u uid, %u nbframes\n",i+1,thrdnum,uid,nbframes[i]);
  279. thrdnum++;
  280. thrdnum = thrdnum%NB_THREADS;
  281. if (i < nbfiles-1){
  282. /* pause */
  283. pause = arr; /*next_arrival(arr);*/
  284. usleep(1000*pause);
  285. }
  286. }
  287. clock_gettime(CLOCK_MONOTONIC, &end_ts);
  288. diff_ts = diff_timespec(start_ts, end_ts);
  289. unsigned long long total_ns = 1000000000*diff_ts.tv_sec + diff_ts.tv_nsec;
  290. float total_secs = (float)total_ns/1000000000.0f;
  291. float rate = (float)nbfiles/total_secs;
  292. fprintf(stdout,"\nSent %u querys in %f secs- %f querys/sec\n",nbfiles,total_secs,rate);
  293. assert(pthread_join(res_thr, NULL)==0);
  294. table_listener(tblskt);
  295. sleep(1);
  296. fprintf(stdout,"Done.\n");
  297. /* cleanup */
  298. free(hashes);
  299. free(nbframes);
  300. zmq_close(pubskt);
  301. zmq_close(tblskt);
  302. zmq_term(ctx);
  303. return 0;
  304. }