File: GB_AxB_saxpy3_fineHash_notM_phase2.c

package info (click to toggle)
suitesparse-graphblas 7.4.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 67,112 kB
  • sloc: ansic: 1,072,243; cpp: 8,081; sh: 512; makefile: 506; asm: 369; python: 125; awk: 10
file content (100 lines) | stat: -rw-r--r-- 4,014 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//------------------------------------------------------------------------------
// GB_AxB_saxpy3_fineHash_notM_phase2: C<!M>=A*B, fine Hash, phase2
//------------------------------------------------------------------------------

// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//------------------------------------------------------------------------------

{

    //--------------------------------------------------------------------------
    // phase2: fine hash task, C(:,j)<!M(:,j)>=A*B(:,j)
    //--------------------------------------------------------------------------

    // M(:,j) is sparse/hyper and scattered into Hf

    // Given Hf [hash] split into (h,f)

    // h == 0  , f == 0 : unlocked and unoccupied.
    // h == i+1, f == 1 : unlocked, occupied by M(i,j)=1.
    //                    C(i,j) is ignored.
    // h == i+1, f == 2 : unlocked, occupied by C(i,j).
    //                    Hx is initialized.

    // h == (anything), f == 3: locked.

    // 1 -> 1 : to ignore, if M(i,j)=1
    // 0 -> 3 : to lock, if i seen for first time
    // 2 -> 3 : to lock, if i seen already
    // 3 -> 2 : to unlock; now i has been seen

    for ( ; pB < pB_end ; pB++)     // scan B(:,j)
    {
        GB_GET_B_kj_INDEX ;         // get index k of B(k,j)
        GB_GET_A_k ;                // get A(:,k)
        if (aknz == 0) continue ;
        GB_GET_B_kj ;               // bkj = B(k,j)

        // scan A(:,k)
        for (int64_t pA = pA_start ; pA < pA_end ; pA++)
        {
            GB_GET_A_ik_INDEX ;     // get index i of A(i,k)
            GB_MULT_A_ik_B_kj ;         // t = A(i,k) * B(k,j)
            int64_t i1 = i + 1 ;        // i1 = one-based index
            int64_t i_unlocked = (i1 << 2) + 2 ;    // (i+1,2)
            int64_t i_masked   = (i1 << 2) + 1 ;    // (i+1,1)
            for (GB_HASH (i))           // find i in hash table
            {
                int64_t hf ;
                GB_ATOMIC_READ
                hf = Hf [hash] ;        // grab the entry
                #if GB_HAS_ATOMIC
                {
                    if (hf == i_unlocked)  // if true, update C(i,j)
                    { 
                        GB_ATOMIC_UPDATE_HX (hash, t) ;// Hx [.]+=t
                        break ;         // C(i,j) has been updated
                    }
                }
                #endif
                if (hf == i_masked) break ; // M(i,j)=1; ignore
                int64_t h = (hf >> 2) ;
                if (h == 0 || h == i1)
                {
                    // h=0: unoccupied, h=i1: occupied by i
                    do // lock the entry
                    { 
                        // do this atomically:
                        // { hf = Hf [hash] ; Hf [hash] |= 3 ; }
                        GB_ATOMIC_CAPTURE_INT64_OR (hf,Hf[hash],3) ;
                    } while ((hf & 3) == 3) ; // owner: f=0,1,2
                    if (hf == 0)            // f == 0
                    { 
                        // C(i,j) is a new entry in C(:,j)
                        // Hx [hash] = t
                        GB_ATOMIC_WRITE_HX (hash, t) ;
                        GB_ATOMIC_WRITE
                        Hf [hash] = i_unlocked ; // unlock entry
                        break ;
                    }
                    if (hf == i_unlocked)   // f == 2
                    { 
                        // C(i,j) already appears in C(:,j)
                        // Hx [hash] += t
                        GB_ATOMIC_UPDATE_HX (hash, t) ;
                        GB_ATOMIC_WRITE
                        Hf [hash] = i_unlocked ; // unlock entry
                        break ;
                    }
                    // hash table occupied, but not with i,
                    // or with i but M(i,j)=1 so C(i,j) ignored
                    GB_ATOMIC_WRITE
                    Hf [hash] = hf ;  // unlock with prior value
                }
            }
        }
    }
}