Browse Source

Merge aa587fdbf4 into e207b3bd13

pull/6185/merge
yok7 GitHub 11 months ago
parent
commit
afd4c1fe4f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
9 changed files with 1081 additions and 111 deletions
  1. +53
    -0
      .github/workflows/cpu-support-test.yml
  2. +37
    -0
      .github/workflows/linux-high-cpu-test.yml
  3. +38
    -0
      .github/workflows/windows-high-cpu-test.yml
  4. +0
    -0
      64
  5. +650
    -107
      src/cpu.cpp
  6. +47
    -4
      src/cpu.h
  7. +5
    -0
      src/platform.h.in
  8. +1
    -0
      tests/CMakeLists.txt
  9. +250
    -0
      tests/test_cpu_large.cpp

+ 53
- 0
.github/workflows/cpu-support-test.yml View File

@@ -0,0 +1,53 @@
name: CPU Support Test

on:
push:
branches: [ feature/support-64plus-cpu ]
pull_request:
branches: [ master ]

jobs:
windows-test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup MSVC
uses: microsoft/setup-msbuild@v2
- name: Build NCNN
run: |
mkdir build
cd build
cmake -G "Visual Studio 17 2022" -A x64 -DNCNN_BUILD_TESTS=ON ..
cmake --build . --config Release --parallel 4
- name: Test CPU functionality
run: |
cd build
if (Test-Path "tests/Release/test_cpu.exe") {
echo "✓ test_cpu.exe compiled successfully"
.\tests\Release\test_cpu.exe
}
- name: Test popcount64 linking
run: |
cd build
ctest -C Release --output-on-failure -R "test_cpu" --parallel 2

linux-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y build-essential cmake
- name: Build NCNN
run: |
mkdir build
cd build
cmake -DNCNN_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
- name: Test CPU functionality
run: |
cd build
./tests/test_cpu
- name: Run tests
run: |
cd build
ctest --output-on-failure --parallel $(nproc)

+ 37
- 0
.github/workflows/linux-high-cpu-test.yml View File

@@ -0,0 +1,37 @@
name: Linux >64 CPU Support Test

on:
push:
branches: [ feature/support-64plus-cpu ]
pull_request:
branches: [ master ]

jobs:
linux-build-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake
- name: Build NCNN
run: |
mkdir build
cd build
cmake -DNCNN_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
- name: Test CPU functionality
run: |
cd build
./tests/test_cpu
- name: Run comprehensive tests
run: |
cd build
ctest --output-on-failure --parallel $(nproc)

+ 38
- 0
.github/workflows/windows-high-cpu-test.yml View File

@@ -0,0 +1,38 @@
name: Windows >64 CPU Support Test

on:
push:
branches: [ feature/support-64plus-cpu ]
pull_request:
branches: [ master ]

jobs:
windows-build-test:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup MSVC
uses: microsoft/setup-msbuild@v2
- name: Build NCNN with MSVC
run: |
mkdir build-msvc
cd build-msvc
cmake -G "Visual Studio 17 2022" -A x64 -DNCNN_BUILD_TESTS=ON ..
cmake --build . --config Release --parallel 4
- name: Test popcount64 linking
run: |
cd build-msvc
if (Test-Path "tests/Release/test_cpu.exe") {
echo "✓ test_cpu.exe compiled successfully"
.\tests\Release\test_cpu.exe
}
- name: Run critical tests
run: |
cd build-msvc
ctest -C Release --output-on-failure -R "test_cpu|test_mat" --parallel 2

+ 0
- 0
64 View File


+ 650
- 107
src/cpu.cpp
File diff suppressed because it is too large
View File


+ 47
- 4
src/cpu.h View File

@@ -22,21 +22,64 @@ class NCNN_EXPORT CpuSet
{
public:
CpuSet();
CpuSet(const CpuSet& other);
CpuSet& operator=(const CpuSet& other);
~CpuSet();

void enable(int cpu);
void disable(int cpu);
void disable_all();
bool is_enabled(int cpu) const;
int num_enabled() const;

public:
// New methods for >64 CPU support
int max_cpu_id() const;
bool is_empty() const;
void set_range(int start_cpu, int end_cpu, bool enabled);

// Platform-specific accessors for backward compatibility
#if defined _WIN32
ULONG_PTR get_legacy_mask() const;
void set_legacy_mask(ULONG_PTR mask);
#endif
#if defined __ANDROID__ || defined __linux__
const cpu_set_t* get_cpu_set() const;
cpu_set_t* get_cpu_set_mutable();
void set_cpu_set(const cpu_set_t* cpuset);
#endif
#if __APPLE__
unsigned int get_legacy_policy() const;
void set_legacy_policy(unsigned int policy);
#endif

private:
void ensure_capacity(int cpu_id);
void copy_from(const CpuSet& other);

// Internal implementation details
static const int FAST_PATH_BITS = 64;
static const int BITS_PER_WORD = 64;

// Fast path for systems with <= 64 CPUs
uint64_t fast_mask;

// Extended path for systems with > 64 CPUs
uint64_t* extended_mask;
int extended_capacity; // in number of uint64_t words
bool use_extended;

// Platform-specific storage for compatibility
#if defined _WIN32
ULONG_PTR mask;
mutable ULONG_PTR legacy_mask_cache;
mutable bool legacy_mask_valid;
#endif
#if defined __ANDROID__ || defined __linux__
cpu_set_t cpu_set;
mutable cpu_set_t* cpu_set_cache;
mutable bool cpu_set_valid;
#endif
#if __APPLE__
unsigned int policy;
mutable unsigned int legacy_policy_cache;
mutable bool legacy_policy_valid;
#endif
};



+ 5
- 0
src/platform.h.in View File

@@ -4,6 +4,8 @@
#ifndef NCNN_PLATFORM_H
#define NCNN_PLATFORM_H



#cmakedefine01 NCNN_STDIO
#cmakedefine01 NCNN_STRING
#cmakedefine01 NCNN_SIMPLEOCV
@@ -313,6 +315,9 @@ static inline void swap_endianness_32(void* x)
#if NCNN_SIMPLESTL
#include "simplestl.h"
#else
// Ensure basic integer types are available when not using simplestl
// Use C header for compatibility with C++03 and simple modes
#include <stdint.h>
#include <algorithm>
#include <list>
#include <vector>


+ 1
- 0
tests/CMakeLists.txt View File

@@ -60,6 +60,7 @@ endif()

ncnn_add_test(c_api)
ncnn_add_test(cpu)
ncnn_add_test(cpu_large)
ncnn_add_test(expression)
ncnn_add_test(paramdict)



+ 250
- 0
tests/test_cpu_large.cpp View File

@@ -0,0 +1,250 @@
// Copyright 2024 Tencent
// SPDX-License-Identifier: BSD-3-Clause

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cpu.h"

// Test CpuSet with >64 CPUs
static int test_cpuset_large()
{
printf("Testing CpuSet with >64 CPUs...\n");

ncnn::CpuSet set;

// Test basic operations with large CPU IDs
const int test_cpus[] = {0, 63, 64, 65, 127, 128, 255, 256, 511, 512, 1023};
const int num_test_cpus = sizeof(test_cpus) / sizeof(test_cpus[0]);

// Initially all should be disabled
for (int i = 0; i < num_test_cpus; i++)
{
if (set.is_enabled(test_cpus[i]))
{
fprintf(stderr, "CPU %d should be disabled initially\n", test_cpus[i]);
return 1;
}
}

if (set.num_enabled() != 0)
{
fprintf(stderr, "Initially no CPUs should be enabled\n");
return 1;
}

if (!set.is_empty())
{
fprintf(stderr, "Initially CpuSet should be empty\n");
return 1;
}

// Enable all test CPUs
for (int i = 0; i < num_test_cpus; i++)
{
set.enable(test_cpus[i]);
}

// Verify they are enabled
for (int i = 0; i < num_test_cpus; i++)
{
if (!set.is_enabled(test_cpus[i]))
{
fprintf(stderr, "CPU %d should be enabled\n", test_cpus[i]);
return 1;
}
}

if (set.num_enabled() != num_test_cpus)
{
fprintf(stderr, "Expected %d enabled CPUs, got %d\n", num_test_cpus, set.num_enabled());
return 1;
}

if (set.is_empty())
{
fprintf(stderr, "CpuSet should not be empty after enabling CPUs\n");
return 1;
}

// Test max_cpu_id
int max_cpu = set.max_cpu_id();
if (max_cpu != 1023)
{
fprintf(stderr, "Expected max CPU ID 1023, got %d\n", max_cpu);
return 1;
}

// Test disable
set.disable(test_cpus[0]);
if (set.is_enabled(test_cpus[0]))
{
fprintf(stderr, "CPU %d should be disabled after disable()\n", test_cpus[0]);
return 1;
}

if (set.num_enabled() != num_test_cpus - 1)
{
fprintf(stderr, "Expected %d enabled CPUs after disable, got %d\n",
num_test_cpus - 1, set.num_enabled());
return 1;
}

// Test set_range
set.disable_all();
set.set_range(100, 200, true);

int expected_range_count = 200 - 100 + 1;
if (set.num_enabled() != expected_range_count)
{
fprintf(stderr, "Expected %d CPUs in range [100,200], got %d\n",
expected_range_count, set.num_enabled());
return 1;
}

for (int i = 100; i <= 200; i++)
{
if (!set.is_enabled(i))
{
fprintf(stderr, "CPU %d should be enabled in range [100,200]\n", i);
return 1;
}
}

// Test copy constructor
ncnn::CpuSet set_copy(set);
if (set_copy.num_enabled() != set.num_enabled())
{
fprintf(stderr, "Copy constructor failed: different num_enabled\n");
return 1;
}

for (int i = 0; i <= 1023; i++)
{
if (set_copy.is_enabled(i) != set.is_enabled(i))
{
fprintf(stderr, "Copy constructor failed: CPU %d state differs\n", i);
return 1;
}
}

// Test assignment operator
ncnn::CpuSet set_assigned;
set_assigned.enable(999);
set_assigned = set;

if (set_assigned.num_enabled() != set.num_enabled())
{
fprintf(stderr, "Assignment operator failed: different num_enabled\n");
return 1;
}

for (int i = 0; i <= 1023; i++)
{
if (set_assigned.is_enabled(i) != set.is_enabled(i))
{
fprintf(stderr, "Assignment operator failed: CPU %d state differs\n", i);
return 1;
}
}

printf("CpuSet large CPU test passed!\n");
return 0;
}

// Test boundary conditions
static int test_cpuset_boundary()
{
printf("Testing CpuSet boundary conditions...\n");

ncnn::CpuSet set;

// Test CPU ID 0
set.enable(0);
if (!set.is_enabled(0))
{
fprintf(stderr, "CPU 0 should be enabled\n");
return 1;
}

// Test exactly 64 CPUs (boundary between fast and extended path)
set.disable_all();
for (int i = 0; i < 64; i++)
{
set.enable(i);
}

if (set.num_enabled() != 64)
{
fprintf(stderr, "Expected 64 enabled CPUs, got %d\n", set.num_enabled());
return 1;
}

// Test 65th CPU (should trigger extended mode)
set.enable(64);
if (set.num_enabled() != 65)
{
fprintf(stderr, "Expected 65 enabled CPUs, got %d\n", set.num_enabled());
return 1;
}

// Test negative CPU ID (should be ignored)
set.enable(-1);
set.disable(-1);
// Should not crash

// Test very large CPU ID
set.enable(10000);
if (!set.is_enabled(10000))
{
fprintf(stderr, "CPU 10000 should be enabled\n");
return 1;
}

printf("CpuSet boundary test passed!\n");
return 0;
}

// Test performance with large CPU sets
static int test_cpuset_performance()
{
printf("Testing CpuSet performance with large CPU sets...\n");

ncnn::CpuSet set;

// Enable many CPUs
const int max_cpu = 2048;
for (int i = 0; i < max_cpu; i += 2) // Enable every other CPU
{
set.enable(i);
}

// Verify count
int expected_count = max_cpu / 2;
if (set.num_enabled() != expected_count)
{
fprintf(stderr, "Expected %d enabled CPUs, got %d\n", expected_count, set.num_enabled());
return 1;
}

// Test copy performance
ncnn::CpuSet set_copy(set);
if (set_copy.num_enabled() != expected_count)
{
fprintf(stderr, "Copy failed: expected %d enabled CPUs, got %d\n",
expected_count, set_copy.num_enabled());
return 1;
}

printf("CpuSet performance test passed!\n");
return 0;
}

int main()
{
return 0
|| test_cpuset_large()
|| test_cpuset_boundary()
|| test_cpuset_performance();
}

Loading…
Cancel
Save