1# tag: run 2 3cimport cython.parallel 4from cython.parallel import prange, threadid 5from cython.view cimport array 6from libc.stdlib cimport malloc, calloc, free, abort 7from libc.stdio cimport puts 8 9import os 10import sys 11 12try: 13 from builtins import next # Py3k 14except ImportError: 15 def next(it): 16 return it.next() 17 18#@cython.test_assert_path_exists( 19# "//ParallelWithBlockNode//ParallelRangeNode[@schedule = 'dynamic']", 20# "//GILStatNode[@state = 'nogil]//ParallelRangeNode") 21def test_prange(): 22 """ 23 >>> test_prange() 24 (9, 9, 45, 45) 25 """ 26 cdef Py_ssize_t i, j, sum1 = 0, sum2 = 0 27 28 with nogil, cython.parallel.parallel(): 29 for i in prange(10, schedule='dynamic'): 30 sum1 += i 31 32 for j in prange(10, nogil=True): 33 sum2 += j 34 35 return i, j, sum1, sum2 36 37def test_descending_prange(): 38 """ 39 >>> test_descending_prange() 40 5 41 """ 42 cdef int i, start = 5, stop = -5, step = -2 43 cdef int sum = 0 44 45 for i in prange(start, stop, step, nogil=True): 46 sum += i 47 48 return sum 49 50def test_prange_matches_range(int start, int stop, int step): 51 """ 52 >>> test_prange_matches_range(0, 8, 3) 53 >>> test_prange_matches_range(0, 9, 3) 54 >>> test_prange_matches_range(0, 10, 3) 55 56 >>> test_prange_matches_range(0, 10, -3) 57 58 >>> test_prange_matches_range(0, -10, -3) 59 >>> test_prange_matches_range(1, -10, -3) 60 >>> test_prange_matches_range(2, -10, -3) 61 >>> test_prange_matches_range(3, -10, -3) 62 """ 63 cdef int i = -765432, range_last = -876543, prange_last = -987654 64 prange_set = set() 65 for i in prange(start, stop, step, nogil=True, num_threads=3): 66 prange_last = i 67 with gil: 68 prange_set.add(i) 69 range_set = set(range(start, stop, step)) 70 assert range_set == prange_set, "missing: %s extra %s" % (sorted(range_set-prange_set), sorted(prange_set - range_set)) 71 for ii in range(start, stop, step): 72 range_last = ii 73 if range_set: 74 assert prange_last == i 75 assert range_last == prange_last 76 77 78def test_propagation(): 79 """ 80 >>> test_propagation() 81 (9, 9, 9, 9, 450, 450) 82 """ 83 cdef int i = 0, j = 0, x = 0, y = 0 84 cdef int sum1 = 0, sum2 = 0 85 86 for i in prange(10, nogil=True): 87 for j in prange(10): 88 sum1 += i 89 90 with nogil, cython.parallel.parallel(): 91 for x in prange(10): 92 for y in prange(10): 93 sum2 += y 94 95 return i, j, x, y, sum1, sum2 96 97# DISABLED, not allowed in OpenMP 3.0 (fails on Windows) 98#def test_unsigned_operands(): 99# """ 100# >>> test_unsigned_operands() 101# 10 102# """ 103# cdef int i 104# cdef int start = -5 105# cdef unsigned int stop = 5 106# cdef int step = 1 107# 108# cdef int steps_taken = 0 109# cdef int *steps_takenp = &steps_taken 110# 111# for i in prange(start, stop, step, nogil=True): 112# steps_taken += 1 113# if steps_takenp[0] > 10: 114# abort() 115# 116# return steps_taken 117 118def test_reassign_start_stop_step(): 119 """ 120 >>> test_reassign_start_stop_step() 121 20 122 """ 123 cdef int start = 0, stop = 10, step = 2 124 cdef int i 125 cdef int sum = 0 126 127 for i in prange(start, stop, step, nogil=True): 128 start = -2 129 stop = 2 130 step = 0 131 132 sum += i 133 134 return sum 135 136def test_closure_parallel_privates(): 137 """ 138 >>> test_closure_parallel_privates() 139 9 9 140 45 45 141 0 0 9 9 142 """ 143 cdef int x 144 145 def test_target(): 146 nonlocal x 147 for x in prange(10, nogil=True): 148 pass 149 return x 150 151 print test_target(), x 152 153 def test_reduction(): 154 nonlocal x 155 cdef int i 156 157 x = 0 158 for i in prange(10, nogil=True): 159 x += i 160 161 return x 162 163 print test_reduction(), x 164 165 def test_generator(): 166 nonlocal x 167 cdef int i 168 169 x = 0 170 yield x 171 x = 2 172 173 for i in prange(10, nogil=True): 174 x = i 175 176 yield x 177 178 g = test_generator() 179 print next(g), x, next(g), x 180 181def test_closure_parallel_with_gil(): 182 """ 183 >>> test_closure_parallel_with_gil() 184 45 185 45 186 """ 187 cdef int sum = 0 188 temp1 = 5 189 temp2 = -5 190 191 def test_reduction(): 192 nonlocal sum, temp1, temp2 193 194 cdef int i 195 196 for i in prange(10, nogil=True): 197 with gil: 198 sum += temp1 + temp2 + i 199 # assert abs(sum - sum) == 0 200 201 return sum 202 203 print test_reduction() 204 print sum 205 206def test_pure_mode(): 207 """ 208 >>> test_pure_mode() 209 0 210 1 211 2 212 3 213 4 214 4 215 3 216 2 217 1 218 0 219 0 220 """ 221 import Cython.Shadow 222 pure_parallel = sys.modules['cython.parallel'] 223 224 for i in pure_parallel.prange(5): 225 print i 226 227 for i in pure_parallel.prange(4, -1, -1, schedule='dynamic', nogil=True): 228 print i 229 230 with pure_parallel.parallel(): 231 print pure_parallel.threadid() 232 233cdef extern from "types.h": 234 ctypedef short actually_long_t 235 ctypedef long actually_short_t 236 237ctypedef int myint_t 238 239def test_nan_init(): 240 """ 241 >>> test_nan_init() 242 """ 243 cdef int mybool = 0 244 cdef int err = 0 245 cdef int *errp = &err 246 247 cdef signed char a1 = 10 248 cdef unsigned char a2 = 10 249 cdef short b1 = 10 250 cdef unsigned short b2 = 10 251 cdef int c1 = 10 252 cdef unsigned int c2 = 10 253 cdef long d1 = 10 254 cdef unsigned long d2 = 10 255 cdef long long e1 = 10 256 cdef unsigned long long e2 = 10 257 258 cdef actually_long_t miss1 = 10 259 cdef actually_short_t miss2 = 10 260 cdef myint_t typedef1 = 10 261 262 cdef float f = 10.0 263 cdef double g = 10.0 264 cdef long double h = 10.0 265 266 cdef void *p = <void *> 10 267 268 with nogil, cython.parallel.parallel(): 269 # First, trick the error checking to make it believe these variables 270 # are initialized after this if 271 272 if mybool: # mybool is always false! 273 a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = e1 = e2 = 0 274 f = g = h = 0.0 275 p = NULL 276 miss1 = miss2 = typedef1 = 0 277 278 if (a1 == 10 or a2 == 10 or 279 b1 == 10 or b2 == 10 or 280 c1 == 10 or c2 == 10 or 281 d1 == 10 or d2 == 10 or 282 e1 == 10 or e2 == 10 or 283 f == 10.0 or g == 10.0 or h == 10.0 or 284 p == <void *> 10 or miss1 == 10 or miss2 == 10 285 or typedef1 == 10): 286 errp[0] = 1 287 288 cdef int i 289 for i in prange(10, nogil=True): 290 # First, trick the error checking to make it believe these variables 291 # are initialized after this if 292 293 if mybool: # mybool is always false! 294 a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = e1 = e2 = 0 295 f = g = h = 0.0 296 p = NULL 297 miss1 = miss2 = typedef1 = 0 298 299 if (a1 == 10 or a2 == 10 or 300 b1 == 10 or b2 == 10 or 301 c1 == 10 or c2 == 10 or 302 d1 == 10 or d2 == 10 or 303 e1 == 10 or e2 == 10 or 304 f == 10.0 or g == 10.0 or h == 10.0 or 305 p == <void *> 10 or miss1 == 10 or miss2 == 10 306 or typedef1 == 10): 307 errp[0] = 1 308 309 if err: 310 raise Exception("One of the values was not initialized to a maximum " 311 "or NaN value") 312 313 c1 = 20 314 with nogil, cython.parallel.parallel(): 315 c1 = 16 316 317 318cdef void nogil_print(char *s) with gil: 319 print s.decode('ascii') 320 321def test_else_clause(): 322 """ 323 >>> test_else_clause() 324 else clause executed 325 """ 326 cdef int i 327 328 for i in prange(5, nogil=True): 329 pass 330 else: 331 nogil_print('else clause executed') 332 333def test_prange_break(): 334 """ 335 >>> test_prange_break() 336 """ 337 cdef int i 338 339 for i in prange(10, nogil=True): 340 if i == 8: 341 break 342 else: 343 nogil_print('else clause executed') 344 345def test_prange_continue(): 346 """ 347 >>> test_prange_continue() 348 else clause executed 349 0 0 350 1 0 351 2 2 352 3 0 353 4 4 354 5 0 355 6 6 356 7 0 357 8 8 358 9 0 359 """ 360 cdef int i 361 cdef int *p = <int *> calloc(10, sizeof(int)) 362 363 if p == NULL: 364 raise MemoryError 365 366 for i in prange(10, nogil=True): 367 if i % 2 != 0: 368 continue 369 370 p[i] = i 371 else: 372 nogil_print('else clause executed') 373 374 for i in range(10): 375 print i, p[i] 376 377 free(p) 378 379def test_nested_break_continue(): 380 """ 381 >>> test_nested_break_continue() 382 6 7 6 7 383 8 384 """ 385 cdef int i, j, result1 = 0, result2 = 0 386 387 for i in prange(10, nogil=True, num_threads=2, schedule='static'): 388 for j in prange(10, num_threads=2, schedule='static'): 389 if i == 6 and j == 7: 390 result1 = i 391 result2 = j 392 break 393 else: 394 continue 395 396 break 397 398 print i, j, result1, result2 399 400 with nogil, cython.parallel.parallel(num_threads=2): 401 for i in prange(10, schedule='static'): 402 if i == 8: 403 break 404 else: 405 continue 406 407 print i 408 409cdef int parallel_return() nogil: 410 cdef int i 411 412 for i in prange(10): 413 if i == 8: 414 return i 415 else: 416 return 1 417 418 return 2 419 420def test_return(): 421 """ 422 >>> test_return() 423 8 424 """ 425 print parallel_return() 426 427def test_parallel_exceptions(): 428 """ 429 >>> test_parallel_exceptions() 430 I am executed first 431 ('propagate me',) 0 432 """ 433 cdef int i, j, sum = 0 434 435 mylist = [] 436 437 try: 438 for i in prange(10, nogil=True): 439 try: 440 for j in prange(10): 441 with gil: 442 raise Exception("propagate me") 443 444 sum += i * j 445 sum += i 446 finally: 447 with gil: 448 mylist.append("I am executed first") 449 except Exception, e: 450 print mylist[0] 451 print e.args, sum 452 453def test_parallel_exceptions_unnested(): 454 """ 455 >>> test_parallel_exceptions_unnested() 456 ('I am executed first', 0) 457 ('propagate me',) 0 458 """ 459 cdef int i, sum = 0 460 461 mylist = [] 462 463 try: 464 with nogil, cython.parallel.parallel(): 465 try: 466 for i in prange(10): 467 with gil: 468 raise Exception("propagate me") 469 470 sum += i 471 finally: 472 with gil: 473 mylist.append(("I am executed first", sum)) 474 except Exception, e: 475 print mylist[0] 476 print e.args, sum 477 478cdef int parallel_exc_cdef() except -3: 479 cdef int i, j 480 for i in prange(10, nogil=True): 481 for j in prange(10, num_threads=6): 482 with gil: 483 raise Exception("propagate me") 484 485 return 0 486 487cdef int parallel_exc_cdef_unnested() except -3: 488 cdef int i 489 for i in prange(10, nogil=True): 490 with gil: 491 raise Exception("propagate me") 492 493 return 0 494 495def test_parallel_exc_cdef(): 496 """ 497 >>> test_parallel_exc_cdef() 498 Traceback (most recent call last): 499 ... 500 Exception: propagate me 501 """ 502 parallel_exc_cdef_unnested() 503 parallel_exc_cdef() 504 505cpdef int parallel_exc_cpdef() except -3: 506 cdef int i, j 507 for i in prange(10, nogil=True): 508 for j in prange(10, num_threads=6): 509 with gil: 510 raise Exception("propagate me") 511 512 return 0 513 514cpdef int parallel_exc_cpdef_unnested() except -3: 515 cdef int i, j 516 for i in prange(10, nogil=True): 517 with gil: 518 raise Exception("propagate me") 519 520 return 0 521 522 523def test_parallel_exc_cpdef(): 524 """ 525 >>> test_parallel_exc_cpdef() 526 Traceback (most recent call last): 527 ... 528 Exception: propagate me 529 """ 530 parallel_exc_cpdef_unnested() 531 parallel_exc_cpdef() 532 533cdef int parallel_exc_nogil_swallow() except -1: 534 cdef int i, j 535 for i in prange(10, nogil=True): 536 try: 537 for j in prange(10): 538 with gil: 539 raise Exception("propagate me") 540 finally: 541 return i 542 543 return 0 544 545cdef int parallel_exc_nogil_swallow_unnested() except -1: 546 cdef int i 547 with nogil: 548 try: 549 for i in prange(10): 550 with gil: 551 raise Exception("propagate me") 552 finally: 553 return i 554 555 return 0 556 557def test_parallel_exc_nogil_swallow(): 558 """ 559 >>> test_parallel_exc_nogil_swallow() 560 execute me 561 execute me 562 """ 563 parallel_exc_nogil_swallow_unnested() 564 print 'execute me' 565 parallel_exc_nogil_swallow() 566 print 'execute me' 567 568def parallel_exc_replace(): 569 """ 570 >>> parallel_exc_replace() 571 Traceback (most recent call last): 572 ... 573 Exception: propagate me instead 574 """ 575 cdef int i, j 576 for i in prange(10, nogil=True): 577 with gil: 578 try: 579 for j in prange(10, nogil=True): 580 with gil: 581 raise Exception("propagate me") 582 except Exception, e: 583 raise Exception("propagate me instead") 584 585 return 0 586 587 588def parallel_exceptions2(): 589 """ 590 >>> parallel_exceptions2() 591 Traceback (most recent call last): 592 ... 593 Exception: propagate me 594 """ 595 cdef int i, j, k 596 597 for i in prange(10, nogil=True): 598 for j in prange(10): 599 for k in prange(10): 600 if i + j + k > 20: 601 with gil: 602 raise Exception("propagate me") 603 break 604 continue 605 return 606 607def test_parallel_with_gil_return(): 608 """ 609 >>> test_parallel_with_gil_return() 610 True 611 45 612 """ 613 cdef int i, sum = 0 614 615 for i in prange(10, nogil=True): 616 with gil: 617 obj = i 618 sum += obj 619 620 print obj in range(10) 621 622 with nogil, cython.parallel.parallel(): 623 with gil: 624 return sum 625 626def test_parallel_with_gil_continue_unnested(): 627 """ 628 >>> test_parallel_with_gil_continue_unnested() 629 20 630 """ 631 cdef int i, sum = 0 632 633 for i in prange(10, nogil=True): 634 with gil: 635 if i % 2: 636 continue 637 638 sum += i 639 640 print sum 641 642 643cdef int inner_parallel_section() nogil: 644 cdef int j, sum = 0 645 for j in prange(10): 646 sum += j 647 return sum 648 649def outer_parallel_section(): 650 """ 651 >>> outer_parallel_section() 652 450 653 """ 654 cdef int i, sum = 0 655 for i in prange(10, nogil=True): 656 sum += inner_parallel_section() 657 return sum 658 659cdef int nogil_cdef_except_clause() nogil except 0: 660 return 1 661 662cdef void nogil_cdef_except_star() nogil except *: 663 pass 664 665def test_nogil_cdef_except_clause(): 666 """ 667 >>> test_nogil_cdef_except_clause() 668 """ 669 cdef int i 670 for i in prange(10, nogil=True): 671 nogil_cdef_except_clause() 672 nogil_cdef_except_star() 673 674def test_num_threads_compile(): 675 cdef int i 676 for i in prange(10, nogil=True, num_threads=2): 677 pass 678 679 with nogil, cython.parallel.parallel(num_threads=2): 680 pass 681 682 with nogil, cython.parallel.parallel(num_threads=2): 683 for i in prange(10): 684 pass 685 686cdef int chunksize() nogil: 687 return 3 688 689def test_chunksize(): 690 """ 691 >>> test_chunksize() 692 45 693 45 694 45 695 """ 696 cdef int i, sum 697 698 sum = 0 699 for i in prange(10, nogil=True, num_threads=2, schedule='static', chunksize=chunksize()): 700 sum += i 701 print sum 702 703 sum = 0 704 for i in prange(10, nogil=True, num_threads=6, schedule='dynamic', chunksize=chunksize()): 705 sum += i 706 print sum 707 708 sum = 0 709 with nogil, cython.parallel.parallel(): 710 for i in prange(10, schedule='guided', chunksize=chunksize()): 711 sum += i 712 print sum 713 714 715cdef class PrintOnDealloc(object): 716 def __dealloc__(self): 717 print "deallocating..." 718 719def error(): 720 raise Exception("propagate me") 721 722def test_clean_temps(): 723 """ 724 >>> test_clean_temps() 725 deallocating... 726 propagate me 727 """ 728 cdef Py_ssize_t i 729 730 try: 731 for i in prange(100, nogil=True, num_threads=1): 732 with gil: 733 x = PrintOnDealloc() + error() 734 except Exception, e: 735 print e.args[0] 736 737 738def test_pointer_temps(double x): 739 """ 740 >>> test_pointer_temps(1.0) 741 4.0 742 """ 743 cdef Py_ssize_t i 744 cdef double* f 745 cdef double[:] arr = array(format="d", shape=(10,), itemsize=sizeof(double)) 746 arr[0] = 4.0 747 arr[1] = 3.0 748 749 for i in prange(10, nogil=True, num_threads=1): 750 f = &arr[0] 751 752 return f[0] 753 754 755def test_prange_in_with(int x, ctx): 756 """ 757 >>> from contextlib import contextmanager 758 >>> @contextmanager 759 ... def ctx(l): yield l 760 >>> test_prange_in_with(4, ctx([0])) 761 6 762 """ 763 cdef int i 764 with ctx as l: 765 for i in prange(x, nogil=True): 766 with gil: 767 l[0] += i 768 return l[0] 769 770 771cdef extern from *: 772 """ 773 #ifdef _OPENMP 774 #define _get_addr(_x, _idx) &_x 775 #else 776 #define _get_addr(_x, _idx) (&_x+_idx) 777 #endif 778 #define address_of_temp(store, temp, idx) store = _get_addr(temp, idx) 779 #define address_of_temp2(store, ignore, temp, idx) store = _get_addr(temp, idx) 780 781 double get_value() { 782 return 1.0; 783 } 784 """ 785 void address_of_temp(...) nogil 786 void address_of_temp2(...) nogil 787 double get_value() nogil except -1.0 # will generate a temp for exception checking 788 789def test_inner_private(): 790 """ 791 Determines if a temp variable is private by taking its address in multiple threads 792 and seeing if they're the same (thread private variables should have different 793 addresses 794 >>> test_inner_private() 795 ok 796 """ 797 cdef double* not_parallel[2] 798 cdef double* inner_vals[2] 799 cdef double* outer_vals[2] 800 cdef Py_ssize_t n, m 801 802 for n in range(2): 803 address_of_temp(not_parallel[n], get_value(), 0) 804 assert not_parallel[0] == not_parallel[1], "Addresses should be the same since they come from the same temp" 805 806 for n in prange(2, num_threads=2, schedule='static', chunksize=1, nogil=True): 807 address_of_temp(outer_vals[n], get_value(), n) 808 for m in prange(1): 809 # second temp just ensures different numbering 810 address_of_temp2(inner_vals[n], get_value(), get_value(), n) 811 812 inner_are_the_same = inner_vals[0] == inner_vals[1] 813 outer_are_the_same = outer_vals[0] == outer_vals[1] 814 815 assert outer_are_the_same == False, "Temporary variables in outer loop should be private" 816 assert inner_are_the_same == False, "Temporary variables in inner loop should be private" 817 818 print('ok') 819