Skip to content

Commit e1269db

Browse files
authored
Merge branch 'OpenMathLib:develop' into lapack1356
2 parents ad7700b + 5d24293 commit e1269db

16 files changed

Lines changed: 552 additions & 9 deletions

‎Jenkinsfile‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ pipeline {
77
stages {
88
stage('Build') {
99
steps {
10-
sh 'make clean && make'
10+
sh 'make MAKE_NB_JOBS=2 clean && make MAKE_NB_JOBS=2'
1111
}
1212
}
1313
stage('CMakeBuild') {
1414
steps {
15-
sh 'sudo apt update && sudo apt install cmake -y && make clean && rm -rf build && mkdir build && cd build && cmake -DDYNAMIC_ARCH=1 .. && make'
15+
sh 'sudo apt update && sudo apt install cmake -y && make -j 2 clean && rm -rf build && mkdir build && cd build && cmake -DDYNAMIC_ARCH=1 .. && make -j 2'
1616
}
1717
}
1818
}

‎Jenkinsfile.pwr‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pipeline {
1111
checkout scm
1212
sh 'sudo apt update'
1313
sh 'sudo apt install gfortran -y'
14-
sh 'make clean && make'
14+
sh 'make MAKE_NB_JOBS=2 clean && make MAKE_NB_JOBS=2'
1515
}
1616
}
1717
stage('Clang build') {
@@ -24,7 +24,7 @@ pipeline {
2424
checkout scm
2525
sh 'sudo apt update'
2626
sh 'sudo apt install -y clang gfortran'
27-
sh 'make clean && make CC=clang'
27+
sh 'make MAKE_NB_JOBS=2 clean && make CC=clang MAKE_NB_JOBS=2'
2828
}
2929
}
3030
}

‎cmake/prebuild.cmake‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,10 @@ endif ()
12781278
set(SGEMM_UNROLL_N 16)
12791279
set(DGEMM_UNROLL_M 64)
12801280
set(DGEMM_UNROLL_N 8)
1281+
if (BUILD_BFLOAT16)
1282+
set(SBGEMM_UNROLL_M 64)
1283+
set(SBGEMM_UNROLL_N 16)
1284+
endif ()
12811285
else ()
12821286
set(SGEMM_UNROLL_M 16)
12831287
set(SGEMM_UNROLL_N 4)

‎common_thread.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ extern int blas_omp_threads_local;
157157
extern int blas_is_num_threads_set_explicitly;
158158

159159
#if defined(ARCH_ARM64) && defined(OS_DARWIN) && defined(__clang__) && (defined(VORTEXM4) || defined(DYNAMIC_ARCH)) && \
160-
!defined(COMPLEX) && !defined(BFLOAT16) && !defined(HFLOAT16)
160+
!defined(COMPLEX) && (!defined(BFLOAT16) || !defined(BGEMM)) && !defined(HFLOAT16)
161161
#include <sys/sysctl.h>
162162
#ifdef DYNAMIC_ARCH
163163
extern char *gotoblas_corename(void);

‎driver/others/memory.c‎

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,51 @@ int get_num_procs(void) {
248248

249249
if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
250250

251+
#if defined(OS_LINUX)
252+
char quota[10];
253+
int period;
254+
float cpuquota;
255+
char cgroupname[200];
256+
char *cgp;
257+
char cg[1000];
258+
int ncpus=nums;
259+
int havequota=0;
260+
FILE *p = fopen("/proc/self/cgroup","r");
261+
if (p) {
262+
memset(cg,0,1000);
263+
memset(cgroupname,0,200);
264+
fscanf(p,"%s",cgroupname);
265+
fclose(p);
266+
if (cgroupname[0] == '0') {
267+
strcpy(cg,"/sys/fs/cgroup");
268+
cgp=strrchr(cgroupname,':');
269+
cgp++;
270+
strcat(cg,cgp);
271+
strcat(cg,"/");
272+
do {
273+
cgp=strrchr(cg,'/');
274+
*cgp='\0';
275+
strcat(cgp,"/cpu.max");
276+
p=fopen(cg,"r");
277+
if (p) {
278+
fscanf(p,"%s %d",quota,&period);
279+
fclose(p);
280+
if (!strstr(quota,"max")) {
281+
havequota = 1;
282+
cpuquota=atof(quota)/period;
283+
ncpus=MIN(ncpus,(int)(0.5+cpuquota));
284+
}
285+
}
286+
*cgp='\0';
287+
} while(cgp-cg>15);
288+
289+
if (havequota && (ncpus < nums)) {
290+
return ncpus;
291+
}
292+
}
293+
}
294+
#endif
295+
251296
#if defined(USE_OPENMP)
252297
#if _OPENMP >= 201511
253298
int i,n;
@@ -1828,6 +1873,51 @@ int get_num_procs(void) {
18281873

18291874
if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
18301875

1876+
#if defined(OS_LINUX)
1877+
char quota[10];
1878+
int period;
1879+
float cpuquota;
1880+
char cgroupname[200];
1881+
char *cgp;
1882+
char cg[1000];
1883+
int ncpus=nums;
1884+
int havequota=0;
1885+
FILE *p = fopen("/proc/self/cgroup","r");
1886+
if (p) {
1887+
memset(cg,0,1000);
1888+
memset(cgroupname,0,200);
1889+
fscanf(p,"%s",cgroupname);
1890+
fclose(p);
1891+
if (cgroupname[0] == '0') {
1892+
strcpy(cg,"/sys/fs/cgroup");
1893+
cgp=strrchr(cgroupname,':');
1894+
cgp++;
1895+
strcat(cg,cgp);
1896+
strcat(cg,"/");
1897+
do {
1898+
cgp=strrchr(cg,'/');
1899+
*cgp='\0';
1900+
strcat(cgp,"/cpu.max");
1901+
p=fopen(cg,"r");
1902+
if (p) {
1903+
fscanf(p,"%s %d",quota,&period);
1904+
fclose(p);
1905+
if (!strstr(quota,"max")) {
1906+
havequota = 1;
1907+
cpuquota=atof(quota)/period;
1908+
ncpus=MIN(ncpus,(int)(0.5+cpuquota));
1909+
}
1910+
}
1911+
*cgp='\0';
1912+
} while(cgp-cg>15);
1913+
1914+
if (havequota && (ncpus < nums)) {
1915+
return ncpus;
1916+
}
1917+
}
1918+
}
1919+
#endif
1920+
18311921
#if defined(USE_OPENMP)
18321922
/* if (omp_get_proc_bind() != omp_proc_bind_false) */
18331923
#if _OPENMP >= 201511

‎kernel/arm64/KERNEL.VORTEXM4‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ DGEMMINCOPY = gemm_ncopy_sme2.c
1919
DGEMMITCOPY = gemm_tcopy_sme2.c
2020
DGEMMONCOPY = ../generic/gemm_ncopy_$(DGEMM_UNROLL_N).c
2121
DGEMMOTCOPY = ../generic/gemm_tcopy_$(DGEMM_UNROLL_N).c
22+
23+
SBGEMM_BETA = ../generic/gemm_beta.c
24+
SBGEMMKERNEL = sbgemm_kernel_sme2.c
25+
SBGEMMINCOPY = sbgemm_ncopy_64_sme2.c
26+
SBGEMMITCOPY = sbgemm_tcopy_64_sme2.c
27+
SBGEMMONCOPY = sbgemm_ncopy_16_sme2.c
28+
SBGEMMOTCOPY = sbgemm_tcopy_16_sme2.c
29+
SBGEMMINCOPYOBJ = sbgemm_incopy$(TSUFFIX).$(SUFFIX)
30+
SBGEMMITCOPYOBJ = sbgemm_itcopy$(TSUFFIX).$(SUFFIX)
31+
SBGEMMONCOPYOBJ = sbgemm_oncopy$(TSUFFIX).$(SUFFIX)
32+
SBGEMMOTCOPYOBJ = sbgemm_otcopy$(TSUFFIX).$(SUFFIX)
2233
DGEMMINCOPYOBJ = dgemm_incopy$(TSUFFIX).$(SUFFIX)
2334
DGEMMITCOPYOBJ = dgemm_itcopy$(TSUFFIX).$(SUFFIX)
2435
DGEMMONCOPYOBJ = dgemm_oncopy$(TSUFFIX).$(SUFFIX)

‎kernel/arm64/sbgemm_kernel_sme2.c‎

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/***************************************************************************
2+
Copyright (c) 2026, The OpenBLAS Project
3+
All rights reserved.
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are
6+
met:
7+
1. Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
2. Redistributions in binary form must reproduce the above copyright
10+
notice, this list of conditions and the following disclaimer in
11+
the documentation and/or other materials provided with the
12+
distribution.
13+
3. Neither the name of the OpenBLAS project nor the names of
14+
its contributors may be used to endorse or promote products
15+
derived from this software without specific prior written permission.
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBLAS PROJECT OR CONTRIBUTORS BE
20+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22+
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
25+
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*****************************************************************************/
27+
28+
/* A panels of the SME2 kernels (sme2_gemm_packed.h) from op(A) with contiguous columns. */
29+
/*
30+
* SME2 bf16 GEMM kernel for a 512-bit streaming vector length, the bfloat16 counterpart of
31+
* gemm_kernel_sme2.c: C += alpha * A * B on the packed panels of the level-3 driver.
32+
*
33+
* BFMOPA ZA32 with .H operands accumulates 2-wide dot products, so one instruction covers
34+
* two k steps: per k pair the kernel zips rows l and l+1 of the standard [k][m] and [k][n]
35+
* panels into the lane layout 2*i + (k & 1) that the outer product needs (a missing second
36+
* row is loaded under a false predicate, which zero-fills). C accumulates in four ZA32
37+
* tiles of 16x16 fp32: tile rows are the wn columns of the block, tile columns the wm rows,
38+
* with the C load/store helpers of sme2_gemm_tile.h.
39+
*
40+
* A panels come in chunks of SBGEMM_UNROLL_M rows ([k][64], the last chunk narrower), the
41+
* B panels of the generic copies in power-of-two groups of SBGEMM_UNROLL_N columns. Without
42+
* SME2 at run time, or in the compiler, plain loops run on the same layout.
43+
*/
44+
45+
#include "common.h"
46+
#include <string.h>
47+
48+
#include "sme2_gemm_detect.h"
49+
50+
#define S2B_UM GEMM_DEFAULT_UNROLL_M
51+
#define S2B_UN GEMM_DEFAULT_UNROLL_N
52+
53+
#if S2B_UM != 64 || S2B_UN != 16
54+
#error "the SME2 sbgemm kernel needs SBGEMM_UNROLL_M 64 and SBGEMM_UNROLL_N 16"
55+
#endif
56+
57+
/* Width of the B panel group at column j0 of n: full groups, then the largest power of two left. */
58+
static inline int s2b_wn(BLASLONG n, BLASLONG j0) {
59+
BLASLONG r = n - j0;
60+
if (r >= S2B_UN) return S2B_UN;
61+
int w = 1;
62+
while (2 * w <= r) w *= 2;
63+
return w;
64+
}
65+
66+
static inline FLOAT s2b_cvt(IFLOAT h) {
67+
unsigned int u = (unsigned int)h << 16;
68+
FLOAT f;
69+
memcpy(&f, &u, sizeof(f));
70+
return f;
71+
}
72+
73+
#ifdef HAVE_SME2_GEMM
74+
#include "sme2_gemm_tile.h"
75+
76+
#if S2_VL != 16 || S2_NR != 64 || S2_NT != 4
77+
#error "the SME2 sbgemm kernel needs a 512-bit streaming vector length"
78+
#endif
79+
80+
/* The file is built with the SME flags of its target (no SME2); the functions here enable SME2 themselves. */
81+
#pragma clang attribute push(__attribute__((target("sme2"))), apply_to = function)
82+
83+
S2_INL void s2b_op(const int SUB, int t, svbool_t p, svbfloat16_t b, svbfloat16_t a) S2_S S2_ZA {
84+
switch (t) {
85+
case 0: SUB ? svmops_za32_bf16_m(0, p, p, b, a) : svmopa_za32_bf16_m(0, p, p, b, a); break;
86+
case 1: SUB ? svmops_za32_bf16_m(1, p, p, b, a) : svmopa_za32_bf16_m(1, p, p, b, a); break;
87+
case 2: SUB ? svmops_za32_bf16_m(2, p, p, b, a) : svmopa_za32_bf16_m(2, p, p, b, a); break;
88+
default: SUB ? svmops_za32_bf16_m(3, p, p, b, a) : svmopa_za32_bf16_m(3, p, p, b, a); break;
89+
}
90+
}
91+
92+
/* ZA += or -= the A panel (wm rows) times the B panel (wn columns) over k steps of the packed layout. */
93+
S2_NOINL void s2b_mac(const int SUB, BLASLONG k, const IFLOAT *a, BLASLONG wm, const IFLOAT *b, BLASLONG wn) S2_S
94+
S2_ZA {
95+
const svbool_t pt = svptrue_b16(); /* BFMOPA governs per 16-bit element */
96+
const svbool_t pm0 = svwhilelt_b16_s32(0, (int32_t)wm);
97+
const svbool_t pm1 = svwhilelt_b16_s32(S2B_UN * 2, (int32_t)wm);
98+
const svbool_t pn = svwhilelt_b16_s32(0, (int32_t)wn);
99+
const svbool_t pf = svpfalse_b();
100+
for (BLASLONG l = 0; l < k; l += 2) {
101+
const int two = l + 1 < k;
102+
const IFLOAT *ar = a + l * wm, *br = b + l * wn;
103+
const svuint16_t e0 = svld1_u16(pm0, ar), e1 = svld1_u16(pm1, ar + S2B_UN * 2);
104+
const svuint16_t o0 = svld1_u16(two ? pm0 : pf, ar + wm), o1 = svld1_u16(two ? pm1 : pf, ar + wm + S2B_UN * 2);
105+
const svbfloat16_t a0 = svreinterpret_bf16_u16(svzip1_u16(e0, o0));
106+
const svbfloat16_t a1 = svreinterpret_bf16_u16(svzip2_u16(e0, o0));
107+
const svbfloat16_t a2 = svreinterpret_bf16_u16(svzip1_u16(e1, o1));
108+
const svbfloat16_t a3 = svreinterpret_bf16_u16(svzip2_u16(e1, o1));
109+
const svbfloat16_t bv = svreinterpret_bf16_u16(svzip1_u16(svld1_u16(pn, br), svld1_u16(two ? pn : pf, br + wn)));
110+
s2b_op(SUB, 0, pt, bv, a0);
111+
s2b_op(SUB, 1, pt, bv, a1);
112+
s2b_op(SUB, 2, pt, bv, a2);
113+
s2b_op(SUB, 3, pt, bv, a3);
114+
}
115+
}
116+
117+
/* Block of wm rows and wn columns of C; sgn 1 for C += alpha AB with alpha = +-1 (the AB part
118+
added or subtracted in ZA), sgn 0 for a general alpha scaled on the way out of ZA. */
119+
S2_NOINL static void s2b_blk(BLASLONG k, const IFLOAT *a, BLASLONG wm, const IFLOAT *b, BLASLONG wn, FLOAT *C,
120+
BLASLONG ldc, FLOAT alpha, int sgn) S2_S S2_ZA {
121+
if (sgn) {
122+
s2_c_load(1, S2_NT, C, ldc, (int)wn, (int)wm, S2_LOAD, (FLOAT)1);
123+
s2b_mac(alpha == (FLOAT)-1, k, a, wm, b, wn);
124+
s2_c_store(1, S2_NT, C, ldc, (int)wn, (int)wm);
125+
} else {
126+
svzero_za();
127+
s2b_mac(0, k, a, wm, b, wn);
128+
s2_c_store_alpha(S2_NT, C, ldc, (int)wn, (int)wm, alpha, 1);
129+
}
130+
}
131+
132+
__arm_new("za") __arm_locally_streaming static void s2b_drive(BLASLONG m, BLASLONG n, BLASLONG k, FLOAT alpha,
133+
const IFLOAT *sa, const IFLOAT *sb, FLOAT *C,
134+
BLASLONG ldc) {
135+
const int sgn = alpha == (FLOAT)1 || alpha == (FLOAT)-1;
136+
for (BLASLONG j0 = 0; j0 < n;) {
137+
const BLASLONG wn = n - j0 >= S2B_UN ? S2B_UN : s2b_wn(n, j0);
138+
const IFLOAT *b = sb + j0 * k;
139+
for (BLASLONG i0 = 0; i0 < m; i0 += S2B_UM) {
140+
const BLASLONG wm = m - i0 < S2B_UM ? m - i0 : S2B_UM;
141+
s2b_blk(k, sa + i0 * k, wm, b, wn, C + i0 + j0 * ldc, ldc, alpha, sgn);
142+
}
143+
j0 += wn;
144+
}
145+
}
146+
147+
#pragma clang attribute pop
148+
#endif
149+
150+
static void s2b_loops(BLASLONG m, BLASLONG n, BLASLONG k, FLOAT alpha, const IFLOAT *sa, const IFLOAT *sb, FLOAT *C,
151+
BLASLONG ldc) {
152+
for (BLASLONG j0 = 0; j0 < n;) {
153+
const BLASLONG wn = s2b_wn(n, j0);
154+
const IFLOAT *b = sb + j0 * k;
155+
for (BLASLONG i0 = 0; i0 < m; i0 += S2B_UM) {
156+
const BLASLONG wm = m - i0 < S2B_UM ? m - i0 : S2B_UM;
157+
const IFLOAT *a = sa + i0 * k;
158+
for (BLASLONG j = 0; j < wn; ++j)
159+
for (BLASLONG i = 0; i < wm; ++i) {
160+
FLOAT s = 0;
161+
for (BLASLONG l = 0; l < k; ++l) s += s2b_cvt(a[l * wm + i]) * s2b_cvt(b[l * wn + j]);
162+
C[i0 + i + (j0 + j) * ldc] += alpha * s;
163+
}
164+
}
165+
j0 += wn;
166+
}
167+
}
168+
169+
int CNAME(BLASLONG m, BLASLONG n, BLASLONG k, FLOAT alpha, IFLOAT *ba, IFLOAT *bb, FLOAT *C, BLASLONG ldc) {
170+
if (m <= 0 || n <= 0 || k <= 0) return 0;
171+
#ifdef HAVE_SME2_GEMM
172+
if (s2_usable()) {
173+
s2b_drive(m, n, k, alpha, ba, bb, C, ldc);
174+
return 0;
175+
}
176+
#endif
177+
s2b_loops(m, n, k, alpha, ba, bb, C, ldc);
178+
return 0;
179+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/***************************************************************************
2+
Copyright (c) 2026, The OpenBLAS Project
3+
All rights reserved.
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are
6+
met:
7+
1. Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
2. Redistributions in binary form must reproduce the above copyright
10+
notice, this list of conditions and the following disclaimer in
11+
the documentation and/or other materials provided with the
12+
distribution.
13+
3. Neither the name of the OpenBLAS project nor the names of
14+
its contributors may be used to endorse or promote products
15+
derived from this software without specific prior written permission.
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBLAS PROJECT OR CONTRIBUTORS BE
20+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22+
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
25+
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*****************************************************************************/
27+
28+
/* A panels of the SME2 kernels (sme2_gemm_packed.h) from op(A) with contiguous columns. */
29+
/* bfloat16 B panels of the SME2 sbgemm kernel from op(B) with contiguous columns,
30+
in [k][w] groups like the A panels (the generic ncopy packs column-major groups). */
31+
32+
#include "common.h"
33+
#include "sme2_sbgemm_copy.h"
34+
35+
int CNAME(BLASLONG m, BLASLONG n, IFLOAT *a, BLASLONG lda, IFLOAT *b) {
36+
for (BLASLONG j0 = 0; j0 < n;) {
37+
const BLASLONG w = s2bc_wn(n, j0);
38+
s2bc_cols(m, w, a + j0 * lda, lda, b);
39+
b += m * w;
40+
j0 += w;
41+
}
42+
return 0;
43+
}

0 commit comments

Comments
 (0)