config.yml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. version: 2.1
  2. orbs:
  3. python: circleci/python@2
  4. commands:
  5. run_chatgpt_api_test:
  6. parameters:
  7. inference_engine:
  8. type: string
  9. model_id:
  10. type: string
  11. expected_output:
  12. type: string
  13. prompt:
  14. type: string
  15. steps:
  16. - run:
  17. name: Run chatgpt api integration test (<<parameters.inference_engine>>, <<parameters.model_id>>)
  18. command: |
  19. source env/bin/activate
  20. # Set CLANG=1 for tinygrad only
  21. if [ "<<parameters.inference_engine>>" = "tinygrad" ]; then
  22. pip install llvmlite
  23. export TOKENIZERS_PARALLELISM=true SUPPORT_BF16=0 CLANG=1
  24. fi
  25. # Start first instance
  26. EXO_HOME="$(pwd)/.exo_cache_node1" DEBUG_DISCOVERY=7 DEBUG=7 exo --inference-engine <<parameters.inference_engine>> \
  27. --node-id "node1" --listen-port 5678 --broadcast-port 5679 --chatgpt-api-port 8000 \
  28. --chatgpt-api-response-timeout 900 --disable-tui > output1.log &
  29. PID1=$!
  30. tail -f output1.log &
  31. TAIL1=$!
  32. # Start second instance
  33. EXO_HOME="$(pwd)/.exo_cache_node2" DEBUG_DISCOVERY=7 DEBUG=7 exo --inference-engine <<parameters.inference_engine>> \
  34. --node-id "node2" --listen-port 5679 --broadcast-port 5678 --chatgpt-api-port 8001 \
  35. --chatgpt-api-response-timeout 900 --disable-tui > output2.log &
  36. PID2=$!
  37. tail -f output2.log &
  38. TAIL2=$!
  39. # Remember to kill the tail processes at the end
  40. trap 'kill $TAIL1 $TAIL2' EXIT
  41. # Wait for discovery
  42. sleep 10
  43. # Function to check if processes are still running
  44. check_processes() {
  45. if ! kill -0 $PID1 2>/dev/null; then
  46. echo "First instance (PID $PID1) died unexpectedly. Log output:"
  47. cat output1.log
  48. exit 1
  49. fi
  50. if ! kill -0 $PID2 2>/dev/null; then
  51. echo "Second instance (PID $PID2) died unexpectedly. Log output:"
  52. cat output2.log
  53. exit 1
  54. fi
  55. }
  56. # Check processes before proceeding
  57. check_processes
  58. echo "Sending request to first instance..."
  59. response_1=$(curl -s http://localhost:8000/v1/chat/completions \
  60. -H "Content-Type: application/json" \
  61. -d '{
  62. "model": "<<parameters.model_id>>",
  63. "messages": [{"role": "user", "content": "<<parameters.prompt>>"}],
  64. "temperature": 0.7
  65. }')
  66. echo "Response 1: $response_1"
  67. # Check processes after first response
  68. check_processes
  69. echo "Sending request to second instance..."
  70. response_2=$(curl -s http://localhost:8001/v1/chat/completions \
  71. -H "Content-Type: application/json" \
  72. -d '{
  73. "model": "<<parameters.model_id>>",
  74. "messages": [{"role": "user", "content": "<<parameters.prompt>>"}],
  75. "temperature": 0.7
  76. }')
  77. echo "Response 2: $response_2"
  78. # Check processes after second response
  79. check_processes
  80. # Stop both instances
  81. kill $PID1 $PID2
  82. echo ""
  83. # Extract content using jq and check if it contains expected output
  84. content1=$(echo "$response_1" | jq -r '.choices[0].message.content')
  85. content2=$(echo "$response_2" | jq -r '.choices[0].message.content')
  86. if [[ "$content1" != *"<<parameters.expected_output>>"* ]] || [[ "$content2" != *"<<parameters.expected_output>>"* ]]; then
  87. echo "Test failed: Response does not match '<<parameters.expected_output>>'"
  88. echo "Response 1 content: $content1"
  89. echo ""
  90. echo "Response 2 content: $content2"
  91. echo "Output of first instance:"
  92. cat output1.log
  93. echo "Output of second instance:"
  94. cat output2.log
  95. exit 1
  96. else
  97. echo "Test passed: Response from both nodes matches '<<parameters.expected_output>>'"
  98. fi
  99. jobs:
  100. unit_test:
  101. macos:
  102. xcode: "16.0.0"
  103. resource_class: m2pro.large
  104. steps:
  105. - checkout
  106. - run:
  107. name: Set up Python
  108. command: |
  109. brew install python@3.12
  110. python3.12 -m venv env
  111. source env/bin/activate
  112. - run:
  113. name: Install dependencies
  114. command: |
  115. source env/bin/activate
  116. pip install --upgrade pip
  117. pip install .
  118. - run:
  119. name: Run tests
  120. command: |
  121. source env/bin/activate
  122. # set TEMPERATURE to 0 for deterministic sampling
  123. echo "Running inference engine tests..."
  124. METAL_DEVICE_WRAPPER_TYPE=1 METAL_DEBUG_ERROR_MODE=0 METAL_XCODE=1 TEMPERATURE=0 python3 -m exo.inference.test_inference_engine
  125. echo "Running tokenizer tests..."
  126. python3 ./test/test_tokenizers.py
  127. python3 ./test/test_model_helpers.py
  128. discovery_integration_test:
  129. macos:
  130. xcode: "16.0.0"
  131. steps:
  132. - checkout
  133. - run:
  134. name: Set up Python
  135. command: |
  136. brew install python@3.12
  137. python3.12 -m venv env
  138. source env/bin/activate
  139. - run:
  140. name: Install dependencies
  141. command: |
  142. source env/bin/activate
  143. pip install --upgrade pip
  144. pip install .
  145. - run:
  146. name: Run discovery integration test
  147. command: |
  148. source env/bin/activate
  149. DEBUG_DISCOVERY=7 DEBUG=7 exo --node-id "node1" --listen-port 5678 --broadcast-port 5679 --chatgpt-api-port 8000 --disable-tui > output1.log 2>&1 &
  150. PID1=$!
  151. DEBUG_DISCOVERY=7 DEBUG=7 exo --node-id "node2" --listen-port 5679 --broadcast-port 5678 --chatgpt-api-port 8001 --disable-tui > output2.log 2>&1 &
  152. PID2=$!
  153. sleep 10
  154. kill $PID1 $PID2
  155. if grep -q "Peer statuses: {\\'node2\\': \\'is_connected=True, health_check=True" output1.log && ! grep -q "Failed to connect peers:" output1.log && grep -q "Peer statuses: {\\'node1\\': \\'is_connected=True, health_check=True" output2.log && ! grep -q "Failed to connect peers:" output2.log; then
  156. echo "Test passed: Both instances discovered each other"
  157. exit 0
  158. else
  159. echo "Test failed: Devices did not discover each other"
  160. echo "Output of first instance:"
  161. cat output1.log
  162. echo "Output of second instance:"
  163. cat output2.log
  164. exit 1
  165. fi
  166. chatgpt_api_integration_test_mlx:
  167. macos:
  168. xcode: "16.0.0"
  169. resource_class: m2pro.large
  170. steps:
  171. - checkout
  172. - run:
  173. name: Set up Python
  174. command: |
  175. brew install python@3.12
  176. python3.12 -m venv env
  177. source env/bin/activate
  178. - run:
  179. name: Install dependencies
  180. command: |
  181. source env/bin/activate
  182. pip install --upgrade pip
  183. pip install .
  184. - run_chatgpt_api_test:
  185. inference_engine: mlx
  186. model_id: llama-3.2-1b
  187. prompt: "Keep responses concise. Who was the king of pop?"
  188. expected_output: "Michael Jackson"
  189. chatgpt_api_integration_test_dummy:
  190. macos:
  191. xcode: "16.0.0"
  192. resource_class: m2pro.large
  193. steps:
  194. - checkout
  195. - run:
  196. name: Set up Python
  197. command: |
  198. brew install python@3.12
  199. python3.12 -m venv env
  200. source env/bin/activate
  201. - run:
  202. name: Install dependencies
  203. command: |
  204. source env/bin/activate
  205. pip install --upgrade pip
  206. pip install .
  207. - run_chatgpt_api_test:
  208. inference_engine: dummy
  209. model_id: dummy
  210. prompt: "Dummy prompt."
  211. expected_output: "dummy"
  212. chatgpt_api_integration_test_tinygrad:
  213. macos:
  214. xcode: "16.0.0"
  215. resource_class: m2pro.large
  216. steps:
  217. - checkout
  218. - run:
  219. name: Set up Python
  220. command: |
  221. brew install python@3.12
  222. python3.12 -m venv env
  223. source env/bin/activate
  224. - run:
  225. name: Install dependencies
  226. command: |
  227. source env/bin/activate
  228. pip install --upgrade pip
  229. pip install .
  230. - run_chatgpt_api_test:
  231. inference_engine: tinygrad
  232. model_id: llama-3.2-1b
  233. prompt: "Keep responses concise. Who was the king of pop?"
  234. expected_output: "Michael Jackson"
  235. chatgpt_api_integration_test_tinygrad_linux:
  236. machine:
  237. image: ubuntu-2204:current
  238. resource_class: xlarge
  239. steps:
  240. - checkout
  241. - run:
  242. name: Set up Python
  243. command: |
  244. export DEBIAN_FRONTEND=noninteractive
  245. export DEBCONF_NONINTERACTIVE_SEEN=true
  246. sudo apt-get update
  247. sudo add-apt-repository -y ppa:deadsnakes/ppa
  248. sudo apt-get update
  249. sudo apt-get install -y python3.12 python3.12-venv clang
  250. python3.12 -m venv env
  251. source env/bin/activate
  252. - run:
  253. name: Install dependencies
  254. command: |
  255. source env/bin/activate
  256. pip install --upgrade pip
  257. pip install .
  258. - run_chatgpt_api_test:
  259. inference_engine: tinygrad
  260. model_id: llama-3.2-1b
  261. prompt: "Keep responses concise. Who was the king of pop?"
  262. expected_output: "Michael Jackson"
  263. measure_pip_sizes:
  264. macos:
  265. xcode: "16.0.0"
  266. steps:
  267. - checkout
  268. - run:
  269. name: Set up Python
  270. command: |
  271. brew install python@3.12
  272. python3.12 -m venv env
  273. source env/bin/activate
  274. - run:
  275. name: Install dependencies and measure sizes
  276. command: |
  277. source env/bin/activate
  278. pip install --upgrade pip
  279. pip install .
  280. python ./extra/pipsize.py --json ./pipsize.json
  281. - store_artifacts:
  282. path: ./pipsize.json
  283. destination: pip-sizes.json
  284. check_line_count:
  285. docker:
  286. - image: cimg/python:3.10
  287. steps:
  288. - checkout
  289. - run:
  290. name: Setup git for PR comparison
  291. command: |
  292. if [[ -n "$CIRCLE_PULL_REQUEST" ]]; then
  293. PR_NUMBER=$(echo $CIRCLE_PULL_REQUEST | rev | cut -d'/' -f1 | rev)
  294. BASE_BRANCH=$(curl -s -H "Circle-Token: $CIRCLE_TOKEN" \
  295. "https://circleci.com/api/v2/project/github/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pipeline/$CIRCLE_WORKFLOW_ID" \
  296. | jq -r '.target_branch')
  297. git clone -b $BASE_BRANCH --single-branch \
  298. https://github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME.git \
  299. base_branch
  300. fi
  301. - run:
  302. name: Install dependencies
  303. command: |
  304. python -m pip install --upgrade pip
  305. pip install tabulate
  306. - run:
  307. name: Run line count check
  308. command: |
  309. if [[ -n "$CIRCLE_PULL_REQUEST" ]]; then
  310. python extra/line_counter.py base_branch .
  311. else
  312. python extra/line_counter.py .
  313. fi
  314. - store_artifacts:
  315. path: line-count-snapshot.json
  316. destination: line-count-snapshot.json
  317. - store_artifacts:
  318. path: line-count-diff.json
  319. destination: line-count-diff.json
  320. - run:
  321. name: Create test results directory
  322. command: |
  323. mkdir -p test-results/line-count
  324. cp line-count-*.json test-results/line-count/
  325. - store_test_results:
  326. path: test-results
  327. workflows:
  328. version: 2
  329. build_and_test:
  330. jobs:
  331. - check_line_count:
  332. filters:
  333. branches:
  334. only: /.*/
  335. tags:
  336. only: /.*/
  337. - unit_test
  338. - discovery_integration_test
  339. - chatgpt_api_integration_test_mlx
  340. - chatgpt_api_integration_test_tinygrad
  341. - chatgpt_api_integration_test_tinygrad_linux
  342. - chatgpt_api_integration_test_dummy
  343. - measure_pip_sizes