blow.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #define ESTR 256
  12. static void
  13. error(char* fmt, ...)
  14. {
  15. va_list v;
  16. char *e, estr[ESTR], *p;
  17. va_start(v, fmt);
  18. e = estr + ESTR;
  19. p = seprint(estr, e, "%s: ", argv0);
  20. p = vseprint(p, e, fmt, v);
  21. p = seprint(p, e, "\n");
  22. va_end(v);
  23. write(2, estr, p-estr);
  24. }
  25. static void
  26. fatal(char* fmt, ...)
  27. {
  28. va_list v;
  29. char *e, estr[ESTR], *p;
  30. va_start(v, fmt);
  31. e = estr + ESTR;
  32. p = seprint(estr, e, "%s: ", argv0);
  33. p = vseprint(p, e, fmt, v);
  34. p = seprint(p, e, "\n");
  35. va_end(v);
  36. write(2, estr, p - estr);
  37. exits("fatal");
  38. }
  39. static void
  40. usage(void)
  41. {
  42. char *e, estr[ESTR], *p;
  43. e = estr + ESTR;
  44. p = seprint(estr, e, "usage: %s"
  45. " [whatever]"
  46. "\n",
  47. argv0);
  48. write(2, estr, p-estr);
  49. exits("usage");
  50. }
  51. #define F(v, o, w) (((v) & ((1<<(w))-1))<<(o))
  52. enum {
  53. X = 0, /* dimension */
  54. Y = 1,
  55. Z = 2,
  56. N = 3,
  57. Chunk = 32, /* granularity of FIFO */
  58. Pchunk = 8, /* Chunks in a packet */
  59. Quad = 16,
  60. };
  61. /*
  62. * Packet header. The hardware requires an 8-byte header
  63. * of which the last two are reserved (they contain a sequence
  64. * number and a header checksum inserted by the hardware).
  65. * The hardware also requires the packet to be aligned on a
  66. * 128-bit boundary for loading into the HUMMER.
  67. */
  68. typedef struct Tpkt Tpkt;
  69. struct Tpkt {
  70. uint8_t sk; /* Skip Checksum Control */
  71. uint8_t hint; /* Hint|Dp|Pid0 */
  72. uint8_t size; /* Size|Pid1|Dm|Dy|VC */
  73. uint8_t dst[N]; /* Destination Coordinates */
  74. uint8_t _6_[2]; /* reserved */
  75. uint8_t _8_[8]; /* protocol header */
  76. uint8_t payload[];
  77. };
  78. /*
  79. * SKIP is a field in .sk giving the number of 2-bytes
  80. * to skip from the top of the packet before including
  81. * the packet bytes into the running checksum.
  82. * SIZE is a field in .size giving the size of the
  83. * packet in 32-byte 'chunks'.
  84. */
  85. #define SKIP(n) F(n, 1, 7)
  86. #define SIZE(n) F(n, 5, 3)
  87. enum {
  88. Sk = 0x01, /* Skip Checksum */
  89. Pid0 = 0x01, /* Destination Group FIFO MSb */
  90. Dp = 0x02, /* Multicast Deposit */
  91. Hzm = 0x04, /* Z- Hint */
  92. Hzp = 0x08, /* Z+ Hint */
  93. Hym = 0x10, /* Y- Hint */
  94. Hyp = 0x20, /* Y+ Hint */
  95. Hxm = 0x40, /* X- Hint */
  96. Hxp = 0x80, /* X+ Hint */
  97. Vcd0 = 0x00, /* Dynamic 0 VC */
  98. Vcd1 = 0x01, /* Dynamic 1 VC */
  99. Vcbn = 0x02, /* Deterministic Bubble VC */
  100. Vcbp = 0x03, /* Deterministic Priority VC */
  101. Dy = 0x04, /* Dynamic Routing */
  102. Dm = 0x08, /* DMA Mode */
  103. Pid1 = 0x10, /* Destination Group FIFO LSb */
  104. };
  105. static int
  106. torusparse(uint8_t d[3], char* item, char* buf)
  107. {
  108. int n;
  109. char *p;
  110. if((p = strstr(buf, item)) == nil || (p != buf && *(p-1) != '\n'))
  111. return -1;
  112. n = strlen(item);
  113. if(strlen(p) < n+sizeof(": x 0 y 0 z 0"))
  114. return -1;
  115. p += n+sizeof(": x ")-1;
  116. if(strncmp(p-4, ": x ", 4) != 0)
  117. return -1;
  118. if((n = strtol(p, &p, 0)) > 255 || *p != ' ' || *(p+1) != 'y')
  119. return -1;
  120. d[0] = n;
  121. if((n = strtol(p+2, &p, 0)) > 255 || *p != ' ' || *(p+1) != 'z')
  122. return -1;
  123. d[1] = n;
  124. if((n = strtol(p+2, &p, 0)) > 255 || (*p != '\n' && *p != '\0'))
  125. return -1;
  126. d[2] = n;
  127. return 0;
  128. }
  129. void
  130. main(int argc, char* argv[])
  131. {
  132. Tpkt *tpkt;
  133. u8int d[N];
  134. char buf[512], *p;
  135. uint64_t r, start, stop;
  136. int count, fd, i, length, mhz, n, x, y, z;
  137. count = 1;
  138. length = Pchunk*Chunk;
  139. mhz = 700;
  140. ARGBEGIN{
  141. default:
  142. usage();
  143. break;
  144. case 'l':
  145. p = EARGF(usage());
  146. if((n = strtol(argv[0], &p, 0)) <= 0 || p == argv[0] || *p != 0)
  147. usage();
  148. if(n % Chunk)
  149. usage();
  150. length = n;
  151. break;
  152. case 'm':
  153. p = EARGF(usage());
  154. if((n = strtol(argv[0], &p, 0)) <= 0 || p == argv[0] || *p != 0)
  155. usage();
  156. mhz = n;
  157. break;
  158. case 'n':
  159. p = EARGF(usage());
  160. if((n = strtol(argv[0], &p, 0)) <= 0 || p == argv[0] || *p != 0)
  161. usage();
  162. count = n;
  163. break;
  164. }ARGEND;
  165. if(argc != 3)
  166. usage();
  167. if((x = strtol(argv[0], &p, 0)) < 0 || *p != 0)
  168. fatal("x invalid: %d\n", argv[0]);
  169. if((y = strtol(argv[1], &p, 0)) < 0 || *p != 0)
  170. fatal("y invalid: %d\n", argv[1]);
  171. if((z = strtol(argv[2], &p, 0)) <= 0 || *p != 0)
  172. fatal("z invalid: %d\n", argv[2]);
  173. z -= 1;
  174. if((fd = open("/dev/torusstatus", OREAD)) < 0)
  175. fatal("open /dev/torusstatus: %r\n");
  176. if((n = read(fd, buf, sizeof(buf))) < 0)
  177. fatal("read /dev/torusstatus: %r\n");
  178. close(fd);
  179. buf[n] = 0;
  180. if(torusparse(d, "size", buf) < 0)
  181. fatal("parse /dev/torusstatus: <%s>\n", buf);
  182. if(x >= d[X] || y >= d[Y] || z >= d[Z])
  183. fatal("destination out of range: %d.%d.%d >= %d.%d.%d",
  184. x, y, z, d[X], d[Y], d[Z]);
  185. if((tpkt = mallocalign(length, Chunk, 0, 0)) == nil)
  186. fatal("mallocalign tpkt\n");
  187. memset(tpkt, 0, length);
  188. tpkt->sk = SKIP(4);
  189. tpkt->hint = 0;
  190. tpkt->size = SIZE(Pchunk-1)|Dy|Vcd0;
  191. tpkt->dst[X] = x;
  192. tpkt->dst[Y] = y;
  193. tpkt->dst[Z] = z;
  194. if((fd = open("/dev/torus", ORDWR)) < 0)
  195. fatal("open /dev/torus: %r\n");
  196. cycles(&start);
  197. for(i = 0; i < count; i++){
  198. n = pwrite(fd, tpkt, length, 0);
  199. if(n < 0)
  200. fatal("write /dev/torus: %r\n", n);
  201. else if(n < length)
  202. fatal("write /dev/torus: short write %d\n", n);
  203. }
  204. cycles(&stop);
  205. close(fd);
  206. r = (count*length);
  207. r *= mhz;
  208. r /= stop - start;
  209. print("%d writes of %d in %llu cycles @ %dMHz = %llu MB/s\n",
  210. count, length, stop - start, mhz, r);
  211. exits(0);
  212. }