237 lines
5.4 KiB
C++
237 lines
5.4 KiB
C++
//
|
|
// SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include "../mlasi.h"
|
|
#include <iostream>
|
|
|
|
// Fix to ensure compatibility with MSVC build
|
|
#if defined(_MSC_VER)
|
|
#define RESTRICT __restrict
|
|
#else
|
|
#define RESTRICT __restrict__
|
|
#endif
|
|
|
|
// Logging macros.
|
|
#ifndef KLEIDIAI_DEBUG_LOGGING
|
|
#define KLEIDIAI_DEBUG_LOGGING 0
|
|
#endif
|
|
#ifndef KLEIDIAI_KERNEL_LOGGING
|
|
#define KLEIDIAI_KERNEL_LOGGING 0
|
|
#endif
|
|
|
|
#if KLEIDIAI_DEBUG_LOGGING ||KLEIDIAI_KERNEL_LOGGING
|
|
#define KLEIDIAI_LOG(tag, msg) \
|
|
do { \
|
|
std::cout << "[KLEIDIAI " << tag << "]: " << __FILE__ << " : " << __LINE__ << " : " << msg << std::endl; \
|
|
} while(false)
|
|
#endif
|
|
|
|
// General logging. "tag" is expected to qualify the type of message.
|
|
#if KLEIDIAI_DEBUG_LOGGING
|
|
// General debug messages.
|
|
#define KLEIDIAI_DEBUG_LOG(msg) KLEIDIAI_LOG("DEBUG", msg)
|
|
#else
|
|
#define KLEIDIAI_DEBUG_LOG(msg)
|
|
#endif
|
|
|
|
#if KLEIDIAI_KERNEL_LOGGING
|
|
// Messages specifically written before a call to kai_run.
|
|
// Note: In cases where a kernel is called in multiple threads, for example MlasTrySimpleParallel,
|
|
// the output order can be inconsistient. The solution is to set the intra-node thread size to 1.
|
|
// If using onnxruntime_perf_test this is done with "--x 1".
|
|
#define KLEIDIAI_KERNEL_LOG(kernel_name) KLEIDIAI_LOG("KERNEL", kernel_name)
|
|
#else
|
|
#define KLEIDIAI_KERNEL_LOG(msg)
|
|
#endif
|
|
|
|
namespace ArmKleidiAI {
|
|
|
|
// By default we should try for SME2 first before falling back to SME.
|
|
inline const bool UseSME2 = MLAS_CPUIDINFO::GetCPUIDInfo().HasArm_SME2();
|
|
inline const bool UseSME = MLAS_CPUIDINFO::GetCPUIDInfo().HasArm_SME();
|
|
inline const std::string_view vendor_name = MLAS_CPUIDINFO::GetCPUIDInfo().GetCPUVendor();
|
|
|
|
// Buffer packing routines.
|
|
//
|
|
size_t
|
|
MLASCALL
|
|
MlasGemmPackBSize(
|
|
CBLAS_TRANSPOSE TransA,
|
|
CBLAS_TRANSPOSE TransB,
|
|
size_t N,
|
|
size_t K
|
|
);
|
|
|
|
bool
|
|
MLASCALL
|
|
MlasGemmPackB(
|
|
CBLAS_TRANSPOSE TransA,
|
|
CBLAS_TRANSPOSE TransB,
|
|
size_t N,
|
|
size_t K,
|
|
const float* B,
|
|
size_t ldb,
|
|
void* PackedB
|
|
);
|
|
|
|
bool
|
|
MLASCALL
|
|
MlasGemvBatch(
|
|
CBLAS_TRANSPOSE TransA,
|
|
CBLAS_TRANSPOSE TransB,
|
|
size_t M,
|
|
size_t N,
|
|
size_t K,
|
|
const MLAS_SGEMM_DATA_PARAMS* Data,
|
|
size_t BatchSize
|
|
);
|
|
|
|
|
|
bool
|
|
MLASCALL
|
|
MlasGemmBatch(
|
|
CBLAS_TRANSPOSE TransA,
|
|
CBLAS_TRANSPOSE TransB,
|
|
size_t M,
|
|
size_t N,
|
|
size_t K,
|
|
const MLAS_SGEMM_DATA_PARAMS* Data,
|
|
size_t BatchSize,
|
|
MLAS_THREADPOOL* ThreadPool
|
|
);
|
|
|
|
#if defined(__aarch64__) && defined(__linux__)
|
|
size_t
|
|
MLASCALL
|
|
MlasSBGemmPackBSize(
|
|
CBLAS_TRANSPOSE TransA,
|
|
CBLAS_TRANSPOSE TransB,
|
|
size_t N,
|
|
size_t K
|
|
);
|
|
|
|
bool
|
|
MLASCALL
|
|
MlasSBGemmPackB(
|
|
CBLAS_TRANSPOSE TransA,
|
|
CBLAS_TRANSPOSE TransB,
|
|
size_t N,
|
|
size_t K,
|
|
const float* B,
|
|
size_t ldb,
|
|
void* PackedB
|
|
);
|
|
|
|
bool
|
|
MLASCALL
|
|
MlasSBGemmBatch(
|
|
CBLAS_TRANSPOSE TransA,
|
|
CBLAS_TRANSPOSE TransB,
|
|
size_t M,
|
|
size_t N,
|
|
size_t K,
|
|
const MLAS_SBGEMM_DATA_PARAMS* Data,
|
|
size_t BatchSize,
|
|
MLAS_THREADPOOL* ThreadPool
|
|
);
|
|
#endif
|
|
|
|
size_t
|
|
MLASCALL
|
|
MlasDynamicQGemmPackBSize(
|
|
size_t N,
|
|
size_t K
|
|
);
|
|
|
|
void
|
|
MLASCALL
|
|
MlasDynamicQGemmPackB(
|
|
size_t N,
|
|
size_t K,
|
|
const int8_t* B,
|
|
const float* Scales,
|
|
const float* Bias,
|
|
void* PackedB
|
|
);
|
|
|
|
//pack symmetric quantized B and dynamic quantized A
|
|
void
|
|
MLASCALL
|
|
MlasDynamicQGemmBatch(
|
|
const MLAS_GEMM_DYN_QUANT_SHAPE_PARAMS& Shape,
|
|
const MLAS_GEMM_DYN_QUANT_DATA_PARAMS* DataParams,
|
|
const size_t BatchN,
|
|
MLAS_THREADPOOL* ThreadPool
|
|
);
|
|
|
|
bool
|
|
MLASCALL
|
|
MlasConvPrepare(MLAS_CONV_PARAMETERS* Parameters,
|
|
size_t Dimensions,
|
|
size_t BatchCount,
|
|
size_t GroupCount,
|
|
size_t InputChannels,
|
|
const int64_t* InputShape,
|
|
const int64_t* KernelShape,
|
|
const int64_t* DilationShape,
|
|
const int64_t* Padding,
|
|
const int64_t* StrideShape,
|
|
const int64_t* OutputShape,
|
|
size_t FilterCount,
|
|
const MLAS_ACTIVATION* Activation,
|
|
size_t* WorkingBufferSize,
|
|
float Beta,
|
|
MLAS_THREADPOOL* ThreadPool);
|
|
|
|
bool
|
|
MLASCALL
|
|
MlasConv(
|
|
const MLAS_CONV_PARAMETERS* Parameters,
|
|
const float* Input,
|
|
const float* Filter,
|
|
const float* Bias,
|
|
float* WorkingBuffer,
|
|
float* Output,
|
|
MLAS_THREADPOOL* ThreadPool
|
|
);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if a wraparound will occur when multiplying two size_t variables
|
|
Uses __builtin_mul_overflow if available on the current system and if not falls back
|
|
to a default implementation to check this wraparound.
|
|
|
|
Arguments:
|
|
|
|
a - Supplies the first number to be muliplied.
|
|
|
|
b - Supplies the second number to be muliplied.
|
|
|
|
out - pointer to a size_t which acts as the return value in success cases.
|
|
|
|
Return Value:
|
|
|
|
Returns false if the operation was successful
|
|
Returns true if wraparound of size_t was detected
|
|
|
|
--*/
|
|
inline bool mul_overflow_size_t_builtin(size_t a, size_t b, size_t* out) {
|
|
#if defined(__has_builtin)
|
|
# if __has_builtin(__builtin_mul_overflow)
|
|
return __builtin_mul_overflow(a, b, out);
|
|
# endif
|
|
#endif
|
|
// Fallback to manual check if builtin not available
|
|
if (b != 0 && a > SIZE_MAX / b) return true;
|
|
if (out) *out = a * b;
|
|
return false;
|
|
}
|