feat: add Apple platform support#85
Conversation
|
Neat idea, looks to be minimal maintenance overhead. Had some comments above. Thanks! |
|
I would also like to see the impact on smaller (100) and larger (100k, 1mm) inputs. |
|
Here you go on test sizes, not sure I saw the other comments above besides 'neat idea' one, were there more than that? 100 to 1mm Elements 1000 iterations per function per input size, 190,000 total samples Trig / Transcendental Functions (vForce)
Key observations:
Absolute Times at 1M Elements...in wall-clock terms, on a M1 laptop (2019, 16mb)
Arithmetic Functions (vDSP)These are neutral-to-marginal across all sizes. The compiler's auto-vectorization matches vDSP for simple operations.
I left this benchmarking stuff in for you to see how I did it but I dont' really mean to commit that stuff! |
|
The comments above were code review inline ones |
…oolchain Replace ios.toolchain.cmake with CMake's built-in iOS/simulator cross-compilation (CMAKE_SYSTEM_NAME=iOS, CMAKE_OSX_SYSROOT, Xcode generator). Update xcframework script for Xcode generator output paths. Remove ta_bench target.
Compare ErrorNumber return value against TA_TEST_PASS instead of TA_SUCCESS to avoid -Wenum-compare between different enumeration types.
|
Thanks. TL;DR; This is very interesting, but will need to be put on hold for a while: We are trying to simplify the TA functions code, not make them even more cryptic with macros/preprocessing. Once @chadfurman and I deliver the simplification... then the way to integrate SIMD optimization will be different. Your work is useful and will find its way in, but not in this form (lets keep your branch for people who can't wait for it!). Details That way TA functions will become simpler "standard C array processing loops". The motivations are two-folds: (2) @chadfurman and I have learn that the AI is performing amazingly well at translating clean-and-simple C to whatever language/platform/optimization you ask for. Like... magic to me. Therefore, such SIMD-like tricks would be better handled as a C -> Apple C/SIMD code -> Apple Binaries translation flow created and maintained by AI (+github CI/CD). I want to reassure everyone that the translated code must pass exhaustive automated test (ta_regtest etc...) such that it works the same everywhere and remains 100% backward compatible... this is also very important for the AI itself because it thrives when there is a solid automated "tests as specs" feedback loop. |
|
An example might help. Here is how the "clean" sin function is defined: And here are all the code translation supported for now: So for your optimization it will appear only in the C generated output. Finally, all these outputs are automatically tested to match the reference (the unoptimized C implementation). (WIP ignore weird indentation and lack of comments... we will fix that later). Comments welcome! |
I wonder if this will all be moot if you're really porting the whole thing to rust but anyway I did this before seeing the migration plan doc in the repo.
Apple Platform Support: iOS/macOS Toolchain + Accelerate Framework SIMD Optimizations
This PR adds first-class Apple platform support to TA-Lib: cross-compilation for iOS/Simulator/macOS via CMake toolchain, and vectorized implementations of 16 TA functions using Apple's Accelerate framework (vDSP/vForce) for up to 6x throughput on Apple Silicon.
iOS / macOS Build Support
cmake/ios.toolchain.cmake) for iOS, Simulator, and macOS cross-compilationIOS/MACOSvariables) with automatic dev tool disabling for iOSbuild-xcframework.sh) for creating universal static librariesscripts/build-ios.sh) for all three slices in one commandAccelerate Framework Optimizations
16 TA functions are vectorized using vecLib's vDSP (SIMD arithmetic) and vForce (SIMD transcendentals) when building on Apple platforms. Controlled by
TA_USE_ACCELERATECMake option (default ON).vForce-optimized (single-input transcendentals):
ACOS, ASIN, ATAN, COS, COSH, EXP, LN, LOG10, SIN, SINH, SQRT, TAN, TANH
vDSP-optimized (dual-input arithmetic):
ADD, SUB, MULT
All optimizations are guarded by
#if defined(TA_USE_ACCELERATE) && !defined(USE_SINGLE_PRECISION_INPUT)and live in hand-written sections that survivegen_codere-runs. The double-precision path is optimized; float variants fall back to scalar code.Dispatch macros in
ta_veclib.hkeep each call site to one line:Benchmark Results
All benchmarks run on Apple Silicon (M-series), 10,000 iterations per function per input size (1,140,000 total samples)
Speedup at 10,000 elements (mean, n=10000)
Trig and transcendental functions see 1.8x-5.6x speedups via vForce NEON SIMD. ADD, SUB, MULT, and SQRT are neutral -- the compiler's auto-vectorization already matches vDSP for simple arithmetic. They're kept on the Accelerate path because they show no regression.
Methodology
Compare output from two benchmark binaries, built from the same source with
TA_USE_ACCELERATEenabled or not. Each binary ran all 18 functions at 100/1000/10000 elements with 10 warmup iterations followed by N timed iterations.scripts/run_bench.sh 10000 # writes bench_results.dbWhat we tested and held back
These functions didn't test as improvements so no accelerate there, here are details on why:
vDSP_vdivDfdivloopvvceilfrintpinstruction; vForce call overhead makes it slowervvfloorfrintminstruction; same overhead issue as CEILvDSP_sveD+vDSP_dotprDper windowvvsqrtover output arrayvDSP_dotprDfor initial sums__sincos()for paired sin/cosKey insight: Accelerate wins when replacing an entire O(n) loop with a single O(n) vForce/vDSP call. It loses when adding O(1) function calls inside an O(n) outer loop.
Profiling Infrastructure Fixes
The
ta_regtest -pprofiling mode was broken on Apple platforms with Accelerate enabled. The root cause:clock()has ~microsecond granularity, and vForce-optimized functions on small inputs (100 elements) complete faster than one clock tick, producingclockDelta == 0, treated as fatal error 612.Fix:. I got the message that the clock wasn't precise enough for benchmarking when using -p for ta_regtest'
clock()withmach_absolute_time()on Apple (nanosecond precision)TIMER_DECL,TIMER_START,TIMER_STOP,TIMER_TICKS_TO_MS, etc.) inta_test_priv.h, eliminating 8 duplicated#ifdefblocks across 3 filestest_util.c's existing pattern)