@@ -250,6 +250,17 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
250250 FLOAT * c ;
251251 job_t * job = (job_t * )args -> common ;
252252
253+ /* Cancellation token forwarded (by gemm_driver) from the thread that
254+ * issued this operation, or NULL. Once cancellation is observed the
255+ * remaining compute (copy/kernel calls) is skipped, but every
256+ * synchronization point - buffer publication and flag clearing - is
257+ * still executed, so sibling threads never deadlock and the operation
258+ * finishes quickly with C left in an unspecified, partially-updated
259+ * state. */
260+ size_t * cancel_slot = args -> cancel_slot ;
261+ size_t cancel_gen = args -> cancel_gen ;
262+ int cancelled = 0 ;
263+
253264 BLASLONG nthreads_m ;
254265 BLASLONG mypos_m , mypos_n ;
255266 BLASLONG divide_rate = DIVIDE_RATE ;
@@ -314,8 +325,10 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
314325 n_to = range_n [mypos + 1 ];
315326 }
316327
317- /* Multiply C by beta if needed */
318- if (beta ) {
328+ cancelled = openblas_cancel_poll (cancel_slot , cancel_gen );
329+
330+ /* Multiply C by beta if needed (skipped when cancelled) */
331+ if (beta && !cancelled ) {
319332#ifndef COMPLEX
320333 if (beta [0 ] != ONE )
321334#else
@@ -342,6 +355,9 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
342355 /* Iterate through steps of k */
343356 for (ls = 0 ; ls < k ; ls += min_l ){
344357
358+ /* Poll for cancellation at block granularity */
359+ if (!cancelled ) cancelled = openblas_cancel_poll (cancel_slot , cancel_gen );
360+
345361 /* Determine step size in k */
346362 min_l = k - ls ;
347363 if (min_l >= GEMM_Q * 2 ) {
@@ -371,10 +387,12 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
371387 }
372388 }
373389
374- /* Copy local region of A into workspace */
375- START_RPCC ();
376- ICOPY_OPERATION (min_l , min_i , a , lda , ls , m_from , sa );
377- STOP_RPCC (copy_A );
390+ /* Copy local region of A into workspace (skipped when cancelled) */
391+ if (!cancelled ) {
392+ START_RPCC ();
393+ ICOPY_OPERATION (min_l , min_i , a , lda , ls , m_from , sa );
394+ STOP_RPCC (copy_A );
395+ }
378396
379397 /* Copy local region of B into workspace and apply kernel */
380398 div_n = (n_to - n_from + divide_rate - 1 ) / divide_rate ;
@@ -389,9 +407,13 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
389407
390408#if defined(FUSED_GEMM ) && !defined(TIMING )
391409
392- /* Fused operation to copy region of B into workspace and apply kernel */
393- FUSED_KERNEL_OPERATION (min_i , MIN (n_to , js + div_n ) - js , min_l , alpha ,
394- sa , buffer [bufferside ], b , ldb , c , ldc , m_from , js , ls );
410+ /* Fused operation to copy region of B into workspace and apply kernel
411+ * (skipped when cancelled; the buffer is still published below so
412+ * sibling threads do not stall) */
413+ if (!cancelled ) cancelled = openblas_cancel_poll (cancel_slot , cancel_gen );
414+ if (!cancelled )
415+ FUSED_KERNEL_OPERATION (min_i , MIN (n_to , js + div_n ) - js , min_l , alpha ,
416+ sa , buffer [bufferside ], b , ldb , c , ldc , m_from , js , ls );
395417
396418#else
397419
@@ -410,6 +432,12 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
410432*/
411433 if (min_jj > GEMM_UNROLL_N ) min_jj = GEMM_UNROLL_N ;
412434#endif
435+ /* Poll for cancellation between blocks; when cancelled, skip the
436+ * copy and kernel but keep iterating so the buffer is still
437+ * published below and sibling threads do not stall */
438+ if (!cancelled ) cancelled = openblas_cancel_poll (cancel_slot , cancel_gen );
439+ if (!cancelled ) {
440+
413441 /* Copy part of local region of B into workspace */
414442 START_RPCC ();
415443 OCOPY_OPERATION (min_l , min_jj , b , ldb , ls , jjs ,
@@ -427,6 +455,8 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
427455 ops += 2 * min_i * min_jj * min_l ;
428456#endif
429457
458+ }
459+
430460 }
431461#endif
432462
@@ -456,7 +486,10 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
456486 STOP_RPCC (waiting2 );
457487 MB ;
458488
459- /* Apply kernel with local region of A and part of other region of B */
489+ /* Apply kernel with local region of A and part of other region of B
490+ * (skipped when cancelled; the flag is still cleared below) */
491+ if (!cancelled ) cancelled = openblas_cancel_poll (cancel_slot , cancel_gen );
492+ if (!cancelled ) {
460493 START_RPCC ();
461494 KERNEL_OPERATION (min_i , MIN (range_n [current + 1 ] - js , div_n ), min_l , alpha ,
462495 sa , (IFLOAT * )job [current ].working [mypos ][CACHE_LINE_SIZE * bufferside ],
@@ -466,6 +499,7 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
466499#ifdef TIMING
467500 ops += 2 * min_i * MIN (range_n [current + 1 ] - js , div_n ) * min_l ;
468501#endif
502+ }
469503 }
470504
471505 /* Clear synchronization flag if this thread is done with other region of B */
@@ -476,9 +510,12 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
476510 }
477511 } while (current != mypos );
478512
479- /* Iterate through steps of m
513+ /* Iterate through steps of m
480514 * Note: First step has already been finished */
481515 for (is = m_from + min_i ; is < m_to ; is += min_i ){
516+ /* Poll for cancellation between blocks */
517+ if (!cancelled ) cancelled = openblas_cancel_poll (cancel_slot , cancel_gen );
518+
482519 min_i = m_to - is ;
483520 if (min_i >= GEMM_P * 2 ) {
484521 min_i = GEMM_P ;
@@ -487,10 +524,12 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
487524 min_i = (((min_i + 1 ) / 2 + GEMM_UNROLL_M - 1 )/GEMM_UNROLL_M ) * GEMM_UNROLL_M ;
488525 }
489526
490- /* Copy local region of A into workspace */
491- START_RPCC ();
492- ICOPY_OPERATION (min_l , min_i , a , lda , ls , is , sa );
493- STOP_RPCC (copy_A );
527+ /* Copy local region of A into workspace (skipped when cancelled) */
528+ if (!cancelled ) {
529+ START_RPCC ();
530+ ICOPY_OPERATION (min_l , min_i , a , lda , ls , is , sa );
531+ STOP_RPCC (copy_A );
532+ }
494533
495534 /* Get regions of B and apply kernel */
496535 current = mypos ;
@@ -500,17 +539,20 @@ static int inner_thread(blas_arg_t *args, BLASLONG *range_m, BLASLONG *range_n,
500539 div_n = (range_n [current + 1 ] - range_n [current ] + divide_rate - 1 ) / divide_rate ;
501540 for (js = range_n [current ], bufferside = 0 ; js < range_n [current + 1 ]; js += div_n , bufferside ++ ) {
502541
503- /* Apply kernel with local region of A and part of region of B */
542+ /* Apply kernel with local region of A and part of region of B
543+ * (skipped when cancelled; the flag is still cleared below) */
544+ if (!cancelled ) {
504545 START_RPCC ();
505546 KERNEL_OPERATION (min_i , MIN (range_n [current + 1 ] - js , div_n ), min_l , alpha ,
506547 sa , (IFLOAT * )job [current ].working [mypos ][CACHE_LINE_SIZE * bufferside ],
507548 c , ldc , is , js );
508549 STOP_RPCC (kernel );
509-
550+
510551#ifdef TIMING
511552 ops += 2 * min_i * MIN (range_n [current + 1 ] - js , div_n ) * min_l ;
512553#endif
513-
554+ }
555+
514556 /* Clear synchronization flag if this thread is done with region of B */
515557 if (is + min_i >= m_to ) {
516558 WMB ;
@@ -688,6 +730,12 @@ static int gemm_driver(blas_arg_t *args, BLASLONG *range_m, BLASLONG
688730 newarg .beta = args -> beta ;
689731 newarg .nthreads = args -> nthreads ;
690732 newarg .common = (void * )job ;
733+
734+ /* Begin a cancellable generation on this (the calling, i.e. issuing)
735+ * thread and forward it to the worker threads through the job
736+ * arguments. */
737+ newarg .cancel_gen = openblas_cancel_begin ();
738+ newarg .cancel_slot = openblas_cancel_self ();
691739#ifdef PARAMTEST
692740 newarg .gemm_p = args -> gemm_p ;
693741 newarg .gemm_q = args -> gemm_q ;
@@ -791,6 +839,11 @@ static int gemm_driver(blas_arg_t *args, BLASLONG *range_m, BLASLONG
791839 WMB ;
792840 /* Execute parallel computation */
793841 exec_blas (nthreads , queue );
842+
843+ /* Skip the remaining column blocks once this operation has been
844+ * cancelled. Each exec_blas() round is a full barrier, so bailing
845+ * out between rounds leaves the library in a consistent state. */
846+ if (openblas_cancel_poll (newarg .cancel_slot , newarg .cancel_gen )) break ;
794847 }
795848
796849#ifdef USE_ALLOC_HEAP
0 commit comments