linux 内核开发之 for_each_online_cpu vs for_each_possible_cpu 详细对比

1. 基本概念区别

1.1 Online CPU vs Possible CPU

// Online CPU:当前正在运行的CPU
// Possible CPU:系统中可能存在的所有CPU(包括当前离线的)

// 理解CPU状态的层次结构:
/*
所有CPU状态层次:
├── Possible CPUs (可能的CPU)
│   ├── Present CPUs (存在的CPU) 
│   │   ├── Online CPUs (在线的CPU)
│   │   │   └── Active CPUs (活跃的CPU)
│   │   └── Offline CPUs (离线的CPU)
│   └── Not Present CPUs (不存在的CPU)
└── Impossible CPUs (不可能的CPU)
*/

// 基本示例
void show_cpu_differences(void) {
    int cpu;

    printk("=== CPU Status Comparison ===\n");

    printk("Possible CPUs (%d total): ", num_possible_cpus());
    for_each_possible_cpu(cpu) {
        printk("%d ", cpu);
    }
    printk("\n");

    printk("Online CPUs (%d total): ", num_online_cpus());
    for_each_online_cpu(cpu) {
        printk("%d ", cpu);
    }
    printk("\n");

    printk("Present CPUs (%d total): ", num_present_cpus());
    for_each_present_cpu(cpu) {
        printk("%d ", cpu);
    }
    printk("\n");
}

/* 典型输出示例:
 * === CPU Status Comparison ===
 * Possible CPUs (8 total): 0 1 2 3 4 5 6 7 
 * Online CPUs (6 total): 0 1 2 3 4 5 
 * Present CPUs (8 total): 0 1 2 3 4 5 6 7 
 * 
 * 说明:系统有8个可能的CPU,都物理存在,但只有6个在线
 */

1.2 CPU状态转换

// CPU状态可以动态改变
void demonstrate_cpu_hotplug(void) {
    int cpu = 2;

    // 检查CPU当前状态
    printk("CPU %d status:\n", cpu);
    printk("  possible: %s\n", cpu_possible(cpu) ? "yes" : "no");
    printk("  present:  %s\n", cpu_present(cpu) ? "yes" : "no"); 
    printk("  online:   %s\n", cpu_online(cpu) ? "yes" : "no");
    printk("  active:   %s\n", cpu_active(cpu) ? "yes" : "no");

    // CPU热插拔操作(需要适当权限)
    /*
    echo 0 > /sys/devices/system/cpu/cpu2/online  // 下线CPU 2
    echo 1 > /sys/devices/system/cpu/cpu2/online  // 上线CPU 2
    */
}

// 状态检查函数
static inline int cpu_possible(int cpu);   // CPU是否可能存在
static inline int cpu_present(int cpu);    // CPU是否物理存在  
static inline int cpu_online(int cpu);     // CPU是否在线
static inline int cpu_active(int cpu);     // CPU是否活跃

2. 使用场景差异

2.1 初始化场景 – 使用 for_each_possible_cpu

// ✅ 正确:初始化所有可能的CPU
DEFINE_PER_CPU(struct cpu_data, cpu_info);
DEFINE_PER_CPU(int, cpu_counter);

static int __init init_percpu_data(void) {
    int cpu;

    printk("Initializing per-CPU data for all possible CPUs\n");

    // 必须初始化所有可能的CPU,包括当前离线的
    for_each_possible_cpu(cpu) {
        struct cpu_data *data = per_cpu_ptr(&cpu_info, cpu);

        // 初始化数据结构
        data->cpu_id = cpu;
        data->state = CPU_STATE_INIT;
        data->counter = 0;
        data->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
        if (!data->buffer) {
            goto cleanup;
        }

        INIT_LIST_HEAD(&data->work_list);
        spin_lock_init(&data->lock);

        // 初始化计数器
        per_cpu(cpu_counter, cpu) = 0;

        printk("  Initialized CPU %d (online: %s)\n", 
               cpu, cpu_online(cpu) ? "yes" : "no");
    }

    return 0;

cleanup:
    // 清理已分配的资源
    for_each_possible_cpu(cpu) {
        struct cpu_data *data = per_cpu_ptr(&cpu_info, cpu);
        if (data->buffer) {
            kfree(data->buffer);
            data->buffer = NULL;
        }
    }
    return -ENOMEM;
}

// ❌ 错误:只初始化在线CPU
static int __init wrong_init_percpu_data(void) {
    int cpu;

    // 错误!如果CPU 2当前离线,就不会被初始化
    // 当CPU 2后来上线时,数据未初始化,可能导致崩溃
    for_each_online_cpu(cpu) {
        struct cpu_data *data = per_cpu_ptr(&cpu_info, cpu);
        data->cpu_id = cpu;  // 只初始化在线CPU
    }

    return 0;
}

/* 问题场景:
 * 1. 系统启动时CPU 2离线
 * 2. wrong_init_percpu_data只初始化CPU 0,1
 * 3. 运行时CPU 2被上线
 * 4. 访问CPU 2的cpu_info时,数据未初始化!
 */

2.2 清理场景 – 使用 for_each_possible_cpu

// ✅ 正确:清理所有可能的CPU
static void __exit cleanup_percpu_data(void) {
    int cpu;

    printk("Cleaning up per-CPU data for all possible CPUs\n");

    // 必须清理所有可能的CPU,包括当前离线的
    for_each_possible_cpu(cpu) {
        struct cpu_data *data = per_cpu_ptr(&cpu_info, cpu);

        if (data->buffer) {
            kfree(data->buffer);
            data->buffer = NULL;
        }

        // 清理列表中可能残留的工作项
        if (!list_empty(&data->work_list)) {
            struct work_item *item, *tmp;
            list_for_each_entry_safe(item, tmp, &data->work_list, list) {
                list_del(&item->list);
                kfree(item);
            }
        }

        printk("  Cleaned up CPU %d\n", cpu);
    }
}

// ❌ 错误:只清理在线CPU
static void __exit wrong_cleanup_percpu_data(void) {
    int cpu;

    // 错误!离线CPU的资源不会被释放
    for_each_online_cpu(cpu) {
        struct cpu_data *data = per_cpu_ptr(&cpu_info, cpu);
        if (data->buffer) {
            kfree(data->buffer);  // 离线CPU的内存泄漏!
        }
    }
}

2.3 统计收集场景 – 使用 for_each_online_cpu

// ✅ 正确:只统计在线CPU的数据
DEFINE_PER_CPU(struct performance_stats, perf_stats);

struct global_performance_stats {
    unsigned long total_operations;
    unsigned long total_errors;
    unsigned long total_time;
    unsigned int active_cpus;
    unsigned int reporting_cpus;
};

void collect_performance_stats(struct global_performance_stats *global) {
    int cpu;

    memset(global, 0, sizeof(*global));

    printk("Collecting performance statistics from online CPUs\n");

    // 只统计在线CPU,离线CPU的数据无意义
    for_each_online_cpu(cpu) {
        struct performance_stats *stats = per_cpu_ptr(&perf_stats, cpu);

        global->total_operations += stats->operations;
        global->total_errors += stats->errors;
        global->total_time += stats->runtime;
        global->reporting_cpus++;

        printk("  CPU %d: ops=%lu, errors=%lu, time=%lu\n",
               cpu, stats->operations, stats->errors, stats->runtime);
    }

    global->active_cpus = num_online_cpus();

    printk("Global stats: %lu ops, %lu errors, %u CPUs\n",
           global->total_operations, global->total_errors, global->active_cpus);
}

// ❌ 错误:统计包括离线CPU
void wrong_collect_stats(struct global_performance_stats *global) {
    int cpu;

    memset(global, 0, sizeof(*global));

    // 错误!离线CPU的统计数据可能是陈旧的或无意义的
    for_each_possible_cpu(cpu) {
        struct performance_stats *stats = per_cpu_ptr(&perf_stats, cpu);
        global->total_operations += stats->operations;  // 包含离线CPU的旧数据
    }
}

2.4 负载均衡场景 – 使用 for_each_online_cpu

// ✅ 正确:负载均衡只考虑在线CPU
DEFINE_PER_CPU(unsigned int, work_queue_length);
DEFINE_PER_CPU(unsigned int, cpu_load_percentage);

int find_least_loaded_cpu(void) {
    int cpu, best_cpu = -1;
    unsigned int min_load = UINT_MAX;

    // 只在在线CPU中查找,离线CPU不能接受工作
    for_each_online_cpu(cpu) {
        unsigned int load = per_cpu(cpu_load_percentage, cpu);
        unsigned int queue_len = per_cpu(work_queue_length, cpu);

        // 综合考虑CPU负载和队列长度
        unsigned int total_load = load + (queue_len * 10);

        if (total_load < min_load) {
            min_load = total_load;
            best_cpu = cpu;
        }

        printk("CPU %d: load=%u%%, queue=%u, total_load=%u\n",
               cpu, load, queue_len, total_load);
    }

    if (best_cpu >= 0) {
        printk("Selected CPU %d (load=%u)\n", best_cpu, min_load);
    }

    return best_cpu;
}

// 工作分配函数
int schedule_work_on_best_cpu(struct work_struct *work) {
    int cpu = find_least_loaded_cpu();

    if (cpu < 0) {
        printk(KERN_ERR "No online CPU available for work\n");
        return -ENODEV;
    }

    // 分配到负载最轻的CPU
    schedule_work_on(cpu, work);
    this_cpu_inc(work_queue_length);

    return 0;
}

3. CPU热插拔场景

3.3 CPU热插拔通知处理

// 处理CPU状态变化
static int percpu_cpu_callback(struct notifier_block *nfb,
                              unsigned long action, void *hcpu) {
    unsigned int cpu = (unsigned long)hcpu;
    struct cpu_data *data = per_cpu_ptr(&cpu_info, cpu);

    switch (action) {
    case CPU_UP_PREPARE:
        printk("CPU %d coming online - preparing\n", cpu);

        // CPU即将上线,确保数据已初始化
        if (!data->buffer) {
            data->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
            if (!data->buffer) {
                printk(KERN_ERR "Failed to allocate buffer for CPU %d\n", cpu);
                return NOTIFY_BAD;
            }
        }

        data->state = CPU_STATE_ONLINE;
        data->online_time = jiffies;
        break;

    case CPU_ONLINE:
        printk("CPU %d is now online\n", cpu);

        // 启动CPU特定的工作
        data->worker_thread = kthread_create_on_cpu(cpu_worker_thread,
                                                   data, cpu, "worker/%u");
        if (!IS_ERR(data->worker_thread)) {
            wake_up_process(data->worker_thread);
        }
        break;

    case CPU_DEAD:
        printk("CPU %d went offline\n", cpu);

        // 停止CPU特定的工作
        if (data->worker_thread) {
            kthread_stop(data->worker_thread);
            data->worker_thread = NULL;
        }

        data->state = CPU_STATE_OFFLINE;
        data->offline_time = jiffies;

        // 注意:不释放内存,CPU可能会重新上线
        break;

    default:
        break;
    }

    return NOTIFY_OK;
}

static struct notifier_block percpu_cpu_notifier = {
    .notifier_call = percpu_cpu_callback,
};

// 注册CPU热插拔通知
static int __init register_cpu_hotplug(void) {
    return register_cpu_notifier(&percpu_cpu_notifier);
}

// 处理CPU状态变化时的数据迁移
void migrate_cpu_data(int src_cpu, int dest_cpu) {
    struct cpu_data *src_data, *dest_data;

    if (!cpu_online(dest_cpu)) {
        printk(KERN_ERR "Destination CPU %d is offline\n", dest_cpu);
        return;
    }

    src_data = per_cpu_ptr(&cpu_info, src_cpu);
    dest_data = per_cpu_ptr(&cpu_info, dest_cpu);

    // 迁移工作队列
    spin_lock(&src_data->lock);
    spin_lock(&dest_data->lock);

    list_splice_tail_init(&src_data->work_list, &dest_data->work_list);
    dest_data->counter += src_data->counter;
    src_data->counter = 0;

    spin_unlock(&dest_data->lock);
    spin_unlock(&src_data->lock);

    printk("Migrated data from CPU %d to CPU %d\n", src_cpu, dest_cpu);
}

4. 实际应用对比示例

4.1 网络子系统统计

// 网络统计的正确实现
struct net_device_stats {
    unsigned long rx_packets;
    unsigned long tx_packets;
    unsigned long rx_bytes;
    unsigned long tx_bytes;
    unsigned long rx_errors;
    unsigned long tx_errors;
};

DEFINE_PER_CPU(struct net_device_stats, net_stats);

// 初始化:使用 for_each_possible_cpu
static int __init init_net_stats(void) {
    int cpu;

    for_each_possible_cpu(cpu) {
        struct net_device_stats *stats = per_cpu_ptr(&net_stats, cpu);
        memset(stats, 0, sizeof(*stats));
        printk("Initialized network stats for CPU %d\n", cpu);
    }

    return 0;
}

// 数据更新:当前CPU操作(自然在在线CPU上)
static inline void update_rx_stats(struct net_device *dev, 
                                  unsigned int len) {
    // 自动在当前CPU上更新,当前CPU必然是在线的
    this_cpu_inc(net_stats.rx_packets);
    this_cpu_add(net_stats.rx_bytes, len);
}

// 统计收集:使用 for_each_online_cpu
void get_net_device_stats(struct net_device *dev, 
                         struct net_device_stats *total) {
    int cpu;

    memset(total, 0, sizeof(*total));

    // 只统计在线CPU的数据
    for_each_online_cpu(cpu) {
        struct net_device_stats *cpu_stats = per_cpu_ptr(&net_stats, cpu);

        total->rx_packets += cpu_stats->rx_packets;
        total->tx_packets += cpu_stats->tx_packets;
        total->rx_bytes += cpu_stats->rx_bytes;
        total->tx_bytes += cpu_stats->tx_bytes;
        total->rx_errors += cpu_stats->rx_errors;
        total->tx_errors += cpu_stats->tx_errors;
    }
}

// 调试信息:显示所有可能的CPU
void debug_net_stats(void) {
    int cpu;

    printk("=== Network Statistics Debug ===\n");

    for_each_possible_cpu(cpu) {
        struct net_device_stats *stats = per_cpu_ptr(&net_stats, cpu);

        printk("CPU %d (%s): RX=%lu/%lu, TX=%lu/%lu\n",
               cpu, cpu_online(cpu) ? "online" : "offline",
               stats->rx_packets, stats->rx_bytes,
               stats->tx_packets, stats->tx_bytes);
    }
}

4.2 内存分配器per-CPU缓存

// 内存分配器的per-CPU缓存实现
#define PERCPU_CACHE_SIZE 64

struct percpu_cache {
    void *objects[PERCPU_CACHE_SIZE];
    int count;
    unsigned long alloc_count;
    unsigned long free_count;
    unsigned long miss_count;
    spinlock_t lock;
};

DEFINE_PER_CPU_ALIGNED(struct percpu_cache, object_cache);

// 初始化:使用 for_each_possible_cpu
static int __init init_percpu_cache(void) {
    int cpu;

    for_each_possible_cpu(cpu) {
        struct percpu_cache *cache = per_cpu_ptr(&object_cache, cpu);

        cache->count = 0;
        cache->alloc_count = 0;
        cache->free_count = 0;
        cache->miss_count = 0;
        spin_lock_init(&cache->lock);

        // 预填充一些对象
        for (int i = 0; i < PERCPU_CACHE_SIZE / 2; i++) {
            cache->objects[i] = kmalloc(OBJECT_SIZE, GFP_KERNEL);
            if (cache->objects[i]) {
                cache->count++;
            }
        }

        printk("Initialized cache for CPU %d with %d objects\n", 
               cpu, cache->count);
    }

    return 0;
}

// 分配:在当前CPU上操作
void *alloc_from_cache(void) {
    struct percpu_cache *cache;
    void *obj = NULL;

    preempt_disable();
    cache = this_cpu_ptr(&object_cache);

    if (cache->count > 0) {
        obj = cache->objects[--cache->count];
        cache->alloc_count++;
    } else {
        cache->miss_count++;
    }

    preempt_enable();

    // 缓存未命中,从全局分配器分配
    if (!obj) {
        obj = kmalloc(OBJECT_SIZE, GFP_KERNEL);
    }

    return obj;
}

// 释放:在当前CPU上操作
void free_to_cache(void *obj) {
    struct percpu_cache *cache;

    if (!obj) return;

    preempt_disable();
    cache = this_cpu_ptr(&object_cache);

    if (cache->count < PERCPU_CACHE_SIZE) {
        cache->objects[cache->count++] = obj;
        cache->free_count++;
        obj = NULL;  // 成功放入缓存
    }

    preempt_enable();

    // 缓存已满,直接释放
    if (obj) {
        kfree(obj);
    }
}

// 统计收集:使用 for_each_online_cpu
void show_cache_statistics(void) {
    int cpu;
    unsigned long total_allocs = 0, total_frees = 0, total_misses = 0;
    unsigned int total_cached = 0;

    printk("=== Per-CPU Cache Statistics ===\n");

    for_each_online_cpu(cpu) {
        struct percpu_cache *cache = per_cpu_ptr(&object_cache, cpu);

        printk("CPU %d: cached=%d, allocs=%lu, frees=%lu, misses=%lu\n",
               cpu, cache->count, cache->alloc_count, 
               cache->free_count, cache->miss_count);

        total_cached += cache->count;
        total_allocs += cache->alloc_count;
        total_frees += cache->free_count;
        total_misses += cache->miss_count;
    }

    printk("Total: cached=%u, allocs=%lu, frees=%lu, misses=%lu\n",
           total_cached, total_allocs, total_frees, total_misses);

    if (total_allocs > 0) {
        printk("Cache hit rate: %lu%%\n", 
               (total_allocs - total_misses) * 100 / total_allocs);
    }
}

// 清理:使用 for_each_possible_cpu
static void __exit cleanup_percpu_cache(void) {
    int cpu;

    for_each_possible_cpu(cpu) {
        struct percpu_cache *cache = per_cpu_ptr(&object_cache, cpu);

        // 释放缓存中的所有对象
        for (int i = 0; i < cache->count; i++) {
            kfree(cache->objects[i]);
        }

        printk("Cleaned up cache for CPU %d (%d objects)\n", 
               cpu, cache->count);
    }
}

5. 性能和行为差异

5.1 性能测试对比

// 性能测试:遍历不同CPU集合的开销
void benchmark_cpu_iteration(void) {
    int iterations = 1000;
    ktime_t start, end;
    s64 duration;
    int cpu, count;

    // 测试 for_each_possible_cpu
    start = ktime_get();
    for (int i = 0; i < iterations; i++) {
        count = 0;
        for_each_possible_cpu(cpu) {
            count++;  // 简单操作
        }
    }
    end = ktime_get();
    duration = ktime_to_ns(ktime_sub(end, start));
    printk("for_each_possible_cpu: %lld ns (%d CPUs scanned)\n",
           duration / iterations, count);

    // 测试 for_each_online_cpu  
    start = ktime_get();
    for (int i = 0; i < iterations; i++) {
        count = 0;
        for_each_online_cpu(cpu) {
            count++;
        }
    }
    end = ktime_get();
    duration = ktime_to_ns(ktime_sub(end, start));
    printk("for_each_online_cpu: %lld ns (%d CPUs scanned)\n",
           duration / iterations, count);

    printk("Performance difference: for_each_online_cpu is typically faster\n");
}

/* 典型结果:
 * for_each_possible_cpu: 1500 ns (8 CPUs scanned)
 * for_each_online_cpu: 900 ns (6 CPUs scanned)  
 * 
 * for_each_online_cpu更快,因为扫描的CPU更少
 */

5.2 正确性验证

// 验证不同遍历的正确性
void verify_cpu_iteration_correctness(void) {
    int cpu, possible_count = 0, online_count = 0;

    printk("=== CPU Iteration Correctness Verification ===\n");

    // 统计各类CPU数量
    for_each_possible_cpu(cpu) {
        possible_count++;
        printk("Possible CPU %d: online=%s, present=%s\n",
               cpu, cpu_online(cpu) ? "yes" : "no",
               cpu_present(cpu) ? "yes" : "no");
    }

    for_each_online_cpu(cpu) {
        online_count++;
        // 验证:在线CPU必须是可能的CPU
        if (!cpu_possible(cpu)) {
            printk(KERN_ERR "ERROR: Online CPU %d is not possible!\n", cpu);
        }
    }

    printk("Verification results:\n");
    printk("  Possible CPUs: %d (num_possible_cpus=%d)\n", 
           possible_count, num_possible_cpus());
    printk("  Online CPUs: %d (num_online_cpus=%d)\n",
           online_count, num_online_cpus());

    // 验证关系:online ⊆ possible
    if (online_count <= possible_count) {
        printk("  ✓ Correct: online_cpus ⊆ possible_cpus\n");
    } else {
        printk("  ✗ ERROR: More online CPUs than possible CPUs!\n");
    }
}

6. 最佳实践总结

6.1 选择决策流程图

// 使用决策辅助函数
enum cpu_iteration_type {
    ITER_POSSIBLE,   // for_each_possible_cpu
    ITER_ONLINE,     // for_each_online_cpu
    ITER_PRESENT     // for_each_present_cpu
};

enum cpu_iteration_type choose_iteration_type(const char *operation) {
    // 初始化/清理操作 -> possible
    if (strstr(operation, "init") || strstr(operation, "cleanup") ||
        strstr(operation, "alloc") || strstr(operation, "free")) {
        return ITER_POSSIBLE;
    }

    // 统计/监控操作 -> online
    if (strstr(operation, "stat") || strstr(operation, "monitor") ||
        strstr(operation, "collect") || strstr(operation, "report")) {
        return ITER_ONLINE;
    }

    // 工作分配 -> online
    if (strstr(operation, "schedule") || strstr(operation, "balance") ||
        strstr(operation, "assign")) {
        return ITER_ONLINE;
    }

    // 硬件相关 -> present
    if (strstr(operation, "hardware") || strstr(operation, "detect")) {
        return ITER_PRESENT;
    }

    // 默认:在线CPU
    return ITER_ONLINE;
}

// 使用示例
void smart_cpu_iteration(const char *operation) {
    enum cpu_iteration_type type = choose_iteration_type(operation);
    int cpu;

    switch (type) {
    case ITER_POSSIBLE:
        printk("Using for_each_possible_cpu for: %s\n", operation);
        for_each_possible_cpu(cpu) {
            handle_cpu_operation(cpu, operation);
        }
        break;

    case ITER_ONLINE:
        printk("Using for_each_online_cpu for: %s\n", operation);
        for_each_online_cpu(cpu) {
            handle_cpu_operation(cpu, operation);
        }
        break;

    case ITER_PRESENT:
        printk("Using for_each_present_cpu for: %s\n", operation);
        for_each_present_cpu(cpu) {
            handle_cpu_operation(cpu, operation);
        }
        break;
    }
}

6.2 综合使用模式

// 综合示例:完整的per-CPU子系统
struct percpu_subsystem {
    const char *name;
    bool initialized;
    atomic_t ref_count;
};

DEFINE_PER_CPU(struct subsystem_data, subsys_data);
static struct percpu_subsystem subsystem = {
    .name = "example_subsystem",
    .initialized = false,
    .ref_count = ATOMIC_INIT(0)
};

// 1. 初始化阶段 - for_each_possible_cpu
static int __init subsystem_init(void) {
    int cpu;

    printk("Initializing %s for all possible CPUs\n", subsystem.name);

    for_each_possible_cpu(cpu) {
        struct subsystem_data *data = per_cpu_ptr(&subsys_data, cpu);

        data->cpu_id = cpu;
        data->state = SUBSYS_STATE_INIT;
        data->buffer = kzalloc(DATA_BUFFER_SIZE, GFP_KERNEL);
        if (!data->buffer) {
            goto cleanup_buffers;
        }

        atomic_set(&data->usage_count, 0);
        spin_lock_init(&data->lock);
        INIT_LIST_HEAD(&data->pending_work);

        printk("  CPU %d: %s\n", cpu, 
               cpu_online(cpu) ? "online" : "offline");
    }

    subsystem.initialized = true;
    printk("%s initialization completed\n", subsystem.name);
    return 0;

cleanup_buffers:
    for_each_possible_cpu(cpu) {
        struct subsystem_data *data = per_cpu_ptr(&subsys_data, cpu);
        if (data->buffer) {
            kfree(data->buffer);
            data->buffer = NULL;
        }
    }
    return -ENOMEM;
}

// 2. 运行时统计 - for_each_online_cpu  
void subsystem_get_statistics(struct global_stats *stats) {
    int cpu;

    if (!subsystem.initialized) {
        memset(stats, 0, sizeof(*stats));
        return;
    }

    memset(stats, 0, sizeof(*stats));
    stats->timestamp = jiffies;

    for_each_online_cpu(cpu) {
        struct subsystem_data *data = per_cpu_ptr(&subsys_data, cpu);

        stats->total_usage += atomic_read(&data->usage_count);
        stats->total_pending += data->pending_count;

        if (data->state == SUBSYS_STATE_ERROR) {
            stats->error_cpus++;
        }

        stats->active_cpus++;
    }

    stats->total_cpus = num_possible_cpus();
    stats->online_cpus = num_online_cpus();
}

// 3. 负载均衡 - for_each_online_cpu
int subsystem_find_best_cpu(void) {
    int cpu, best_cpu = -1;
    int min_usage = INT_MAX;

    if (!subsystem.initialized) {
        return -1;
    }

    for_each_online_cpu(cpu) {
        struct subsystem_data *data = per_cpu_ptr(&subsys_data, cpu);
        int usage = atomic_read(&data->usage_count) + data->pending_count;

        if (data->state == SUBSYS_STATE_ACTIVE && usage < min_usage) {
            min_usage = usage;
            best_cpu = cpu;
        }
    }

    return best_cpu;
}

// 4. 运行时更新 - 当前CPU
void subsystem_process_work(struct work_item *work) {
    struct subsystem_data *data;

    if (!subsystem.initialized) {
        return;
    }

    // 在当前CPU上处理工作(当前CPU肯定是在线的)
    atomic_inc(&subsystem.ref_count);

    preempt_disable();
    data = this_cpu_ptr(&subsys_data);

    atomic_inc(&data->usage_count);
    data->last_work_time = jiffies;

    // 处理工作项
    process_work_item(data, work);

    atomic_dec(&data->usage_count);
    preempt_enable();

    atomic_dec(&subsystem.ref_count);
}

// 5. 清理阶段 - for_each_possible_cpu
static void __exit subsystem_exit(void) {
    int cpu;

    printk("Cleaning up %s\n", subsystem.name);

    // 等待所有工作完成
    while (atomic_read(&subsystem.ref_count) > 0) {
        schedule_timeout(1);
    }

    // 清理所有可能的CPU
    for_each_possible_cpu(cpu) {
        struct subsystem_data *data = per_cpu_ptr(&subsys_data, cpu);

        // 清理pending工作
        if (!list_empty(&data->pending_work)) {
            struct work_item *item, *tmp;
            list_for_each_entry_safe(item, tmp, &data->pending_work, list) {
                list_del(&item->list);
                kfree(item);
            }
        }

        // 释放缓冲区
        if (data->buffer) {
            kfree(data->buffer);
            data->buffer = NULL;
        }

        data->state = SUBSYS_STATE_CLEANUP;
    }

    subsystem.initialized = false;
    printk("%s cleanup completed\n", subsystem.name);
}

module_init(subsystem_init);
module_exit(subsystem_exit);

总结

关键区别:

操作类型使用接口原因
初始化for_each_possible_cpu必须为所有可能的CPU准备数据,即使当前离线
清理for_each_possible_cpu必须清理所有CPU的资源,避免内存泄漏
统计收集for_each_online_cpu只统计活跃的CPU,离线CPU数据无意义
工作分配for_each_online_cpu只能向在线CPU分配工作
负载均衡for_each_online_cpu离线CPU不参与负载均衡
调试显示for_each_possible_cpu显示完整的系统状态

选择原则:

  • 需要完整覆盖(初始化、清理)→ for_each_possible_cpu
  • 需要当前状态(统计、负载)→ for_each_online_cpu
  • 性能敏感的操作 → for_each_online_cpu(扫描CPU更少)
本文版权归原作者zhaofujian所有,采用 CC BY-NC-ND 4.0 协议进行许可,转载请注明出处。

发表评论