app.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright (C) 2025 Midokura Japan KK. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <sys/stat.h>
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <fcntl.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <wamr/wasi_ephemeral_nn.h>
  14. /*
  15. * what this application does is basically same as:
  16. * https://github.com/bytecodealliance/wasmtime/tree/efa236e58d09570baaf27865da33fb852fcf40a5/crates/wasi-nn/examples/classification-example
  17. *
  18. * map_file/unmap_file are copy-and-pasted from:
  19. * https://github.com/yamt/toywasm/blob/0eaad8cacd0cc7692946ff19b25994f106113be8/lib/fileio.c
  20. */
  21. int
  22. map_file(const char *path, void **pp, size_t *sizep)
  23. {
  24. void *p;
  25. size_t size;
  26. ssize_t ssz;
  27. int fd;
  28. int ret;
  29. fd = open(path, O_RDONLY);
  30. if (fd == -1) {
  31. ret = errno;
  32. assert(ret != 0);
  33. return ret;
  34. }
  35. struct stat st;
  36. ret = fstat(fd, &st);
  37. if (ret == -1) {
  38. ret = errno;
  39. assert(ret != 0);
  40. close(fd);
  41. return ret;
  42. }
  43. size = st.st_size;
  44. if (size > 0) {
  45. p = malloc(size);
  46. }
  47. else {
  48. /* Avoid a confusing error */
  49. p = malloc(1);
  50. }
  51. if (p == NULL) {
  52. close(fd);
  53. return ENOMEM;
  54. }
  55. ssz = read(fd, p, size);
  56. if (ssz != size) {
  57. ret = errno;
  58. assert(ret != 0);
  59. close(fd);
  60. return ret;
  61. }
  62. close(fd);
  63. *pp = p;
  64. *sizep = size;
  65. return 0;
  66. }
  67. void
  68. unmap_file(void *p, size_t sz)
  69. {
  70. free(p);
  71. }
  72. static void
  73. print_result(const float *result, size_t sz)
  74. {
  75. /*
  76. * just dump the raw result.
  77. * you can postprocess the output with eg. "sort -k2nr | head"
  78. */
  79. int i;
  80. for (i = 0; i < sz / sizeof(float); i++) {
  81. printf("%d %f\n", i, result[i]);
  82. }
  83. }
  84. int
  85. main(int argc, char **argv)
  86. {
  87. wasi_ephemeral_nn_error nnret;
  88. int ret;
  89. void *xml;
  90. size_t xmlsz;
  91. ret = map_file("fixture/model.xml", &xml, &xmlsz);
  92. if (ret != 0) {
  93. fprintf(stderr, "failed to load fixture/model.xml: %s\n",
  94. strerror(ret));
  95. exit(1);
  96. }
  97. void *weights;
  98. size_t weightssz;
  99. ret = map_file("fixture/model.bin", &weights, &weightssz);
  100. if (ret != 0) {
  101. fprintf(stderr, "failed to load fixture/model.bin: %s\n",
  102. strerror(ret));
  103. exit(1);
  104. }
  105. /* note: openvino takes two buffers, namely IR and weights */
  106. wasi_ephemeral_nn_graph_builder builders[2] = { {
  107. .buf = xml,
  108. .size = xmlsz,
  109. },
  110. {
  111. .buf = weights,
  112. .size = weightssz,
  113. } };
  114. wasi_ephemeral_nn_graph g;
  115. nnret =
  116. wasi_ephemeral_nn_load(builders, 2, wasi_ephemeral_nn_encoding_openvino,
  117. wasi_ephemeral_nn_target_cpu, &g);
  118. unmap_file(xml, xmlsz);
  119. unmap_file(weights, weightssz);
  120. if (nnret != wasi_ephemeral_nn_error_success) {
  121. fprintf(stderr, "load failed with %d\n", (int)nnret);
  122. exit(1);
  123. }
  124. wasi_ephemeral_nn_graph_execution_context ctx;
  125. nnret = wasi_ephemeral_nn_init_execution_context(g, &ctx);
  126. if (nnret != wasi_ephemeral_nn_error_success) {
  127. fprintf(stderr, "init_execution_context failed with %d\n", (int)nnret);
  128. exit(1);
  129. }
  130. void *tensordata;
  131. size_t tensordatasz;
  132. ret = map_file("fixture/tensor.bgr", &tensordata, &tensordatasz);
  133. if (ret != 0) {
  134. fprintf(stderr, "failed to load fixture/tensor.bgr: %s\n",
  135. strerror(ret));
  136. exit(1);
  137. }
  138. wasi_ephemeral_nn_tensor tensor = {
  139. .dimensions = { .buf = (uint32_t[]){1, 3, 224, 224,}, .size = 4, },
  140. .type = wasi_ephemeral_nn_type_fp32,
  141. .data.buf = tensordata,
  142. .data.size = tensordatasz,
  143. };
  144. nnret = wasi_ephemeral_nn_set_input(ctx, 0, &tensor);
  145. unmap_file(tensordata, tensordatasz);
  146. if (nnret != wasi_ephemeral_nn_error_success) {
  147. fprintf(stderr, "set_input failed with %d\n", (int)nnret);
  148. exit(1);
  149. }
  150. nnret = wasi_ephemeral_nn_compute(ctx);
  151. if (nnret != wasi_ephemeral_nn_error_success) {
  152. fprintf(stderr, "compute failed with %d\n", (int)nnret);
  153. exit(1);
  154. }
  155. float result[1001];
  156. uint32_t resultsz;
  157. nnret = wasi_ephemeral_nn_get_output(ctx, 0, (void *)result, sizeof(result),
  158. &resultsz);
  159. if (nnret != wasi_ephemeral_nn_error_success) {
  160. fprintf(stderr, "get_output failed with %d\n", (int)nnret);
  161. exit(1);
  162. }
  163. print_result(result, resultsz);
  164. }