华为OD机试 - 区块链文件转储系统(Python/JS/C/C++ 2024 E卷 200分)

在这里插入图片描述

华为OD机试 2024E卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

区块链底层存储是一个链式文件系统,由顺序的N个文件组成,每个文件的大小不一,依次为F1,F2…Fn。

随着时间的推移,所占存储会越来越大。

云平台考虑将区块链按文件转储到廉价的SATA盘,只有连续的区块链文件才能转储到SATA盘上,且转储的文件之和不能超过SATA盘的容量。

假设每块SATA盘容量为M,求能转储的最大连续文件大小之和。

二、输入描述

第一行为SATA盘容量M,1000<=M<=1000000

第二行为区块链文件大小序列F1,F2…Fn。其中 1<=n<=100000, 1<=Fi<=500

三、输出描述

求能转储的最大连续文件大小之和

四、测试用例

1、输入

1000
100 300 500 400 400 150 100

2、输出

950

3、说明

最大序列和为950,序列为[400,400,150]。

五、解题思路

  1. 使用双指针法遍历文件序列arr,通过移动指针来找到能转储的最大连续文件大小之和;
  2. 将当前文件大小加到curr上;
  3. 如果curr小于等于M,更新ret为curr和ret中的较大值,右指针r向右移动一位;
  4. 如果curr大于M,说明当前连续文件大小之和超过了SATA盘容量,需要调整边界来找到新的连续文件;
  5. 输出能转储的最大连续文件大小之和ret;

六、Python算法源码

# 导入必要的库
import sys

def main():
    # 读取标准输入的所有行,并去除末尾的换行符
    lines = sys.stdin.read().splitlines()
    
    # 第1行:SATA盘容量M,转换为整数
    M = int(lines[0])
    
    # 第2行:区块链文件大小序列,转换为整数列表
    arr = list(map(int, lines[1].split()))
    
    # 序列arr的长度n
    n = len(arr)
    
    # 连续文件的左边界l,初始为0
    l = 0
    # 连续文件的右边界r,初始为0
    r = 0
    # 当前连续文件大小之和curr,初始为0
    curr = 0
    # 能转储的最大连续文件大小之和ret,初始为0
    ret = 0
    
    # 使用双指针法遍历文件序列arr,通过移动指针来找到能转储的最大连续文件大小之和
    while r < n:
        # 将当前文件大小加到curr上
        curr += arr[r]
        
        # 如果curr小于等于M,更新ret为curr和ret中的较大值,右指针r向右移动一位
        if curr <= M:
            ret = max(ret, curr)
            r += 1
        else:
            # 如果curr大于M,说明当前连续文件大小之和超过了SATA盘容量,需要调整边界来找到新的连续文件
            # 将左指针l指向的文件大小从curr中减去
            curr -= arr[l]
            # 左指针l向右移动一位
            l += 1
    
    # 输出能转储的最大连续文件大小之和ret
    print(ret)

# 调用主函数
if __name__ == "__main__":
    main()

七、JavaScript算法源码

// 定义资源分配函数
function main() {
    const fs = require('fs');
    // 读取所有输入内容,并按行分割
    const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n');
    
    // 第1行:SATA盘容量M,转换为整数
    const M = parseInt(input[0]);
    
    // 第2行:区块链文件大小序列,转换为整数数组
    const arr = input[1].split(' ').map(Number);
    
    // 序列arr的长度n
    const n = arr.length;
    
    // 连续文件的左边界l,初始为0
    let l = 0;
    // 连续文件的右边界r,初始为0
    let r = 0;
    // 当前连续文件大小之和curr,初始为0
    let curr = 0;
    // 能转储的最大连续文件大小之和ret,初始为0
    let ret = 0;
    
    // 使用双指针法遍历文件序列arr,通过移动指针来找到能转储的最大连续文件大小之和
    while (r < n) {
        // 将当前文件大小加到curr上
        curr += arr[r];
        
        // 如果curr小于等于M,更新ret为curr和ret中的较大值,右指针r向右移动一位
        if (curr <= M) {
            ret = Math.max(ret, curr);
            r += 1;
        } else {
            // 如果curr大于M,说明当前连续文件大小之和超过了SATA盘容量,需要调整边界来找到新的连续文件
            // 将左指针l指向的文件大小从curr中减去
            curr -= arr[l];
            // 左指针l向右移动一位
            l += 1;
        }
    }
    
    // 输出能转储的最大连续文件大小之和ret
    console.log(ret);
}

// 调用主函数
main();

八、C算法源码

#include <stdio.h>

// 主函数
int main() {
    int M; // 定义SATA盘容量M
    // 读取SATA盘容量M
    scanf("%d", &M);
    
    // 定义文件大小数组,最大可能为100000个文件
    int arr[100000];
    int n = 0; // 文件数量初始化为0
    
    // 读取区块链文件大小序列,直到换行或文件结束
    while (scanf("%d", &arr[n]) != EOF) {
        n++;
        // 防止数组越界
        if (n >= 100000) {
            break;
        }
    }
    
    int l = 0; // 连续文件的左边界l,初始为0
    int r = 0; // 连续文件的右边界r,初始为0
    long long curr = 0; // 当前连续文件大小之和curr,使用long long防止溢出
    long long ret = 0; // 能转储的最大连续文件大小之和ret,使用long long
    
    // 使用双指针法遍历文件序列arr,通过移动指针来找到能转储的最大连续文件大小之和
    while (r < n) {
        // 将当前文件大小加到curr上
        curr += arr[r];
        
        // 如果curr小于等于M,更新ret为curr和ret中的较大值,右指针r向右移动一位
        if (curr <= M) {
            if (curr > ret) {
                ret = curr;
            }
            r++;
        } else {
            // 如果curr大于M,说明当前连续文件大小之和超过了SATA盘容量,需要调整边界来找到新的连续文件
            // 将左指针l指向的文件大小从curr中减去
            curr -= arr[l];
            // 左指针l向右移动一位
            l++;
        }
    }
    
    // 输出能转储的最大连续文件大小之和ret
    printf("%lld\n", ret);
    
    return 0; // 程序结束
}

九、C++算法源码

#include <iostream>
#include <vector>
using namespace std;

// 主函数
int main(){
    ios::sync_with_stdio(false); // 关闭同步,提高输入输出效率
    cin.tie(0); // 取消cin和cout的绑定
    
    long long M; // 定义SATA盘容量M,使用long long防止溢出
    cin >> M; // 读取SATA盘容量M
    
    vector<int> arr; // 定义文件大小数组
    int num;
    // 读取区块链文件大小序列,直到换行或文件结束
    while(cin >> num){
        arr.push_back(num);
    }
    
    int n = arr.size(); // 文件数量
    int l = 0; // 连续文件的左边界l,初始为0
    int r = 0; // 连续文件的右边界r,初始为0
    long long curr = 0; // 当前连续文件大小之和curr
    long long ret = 0; // 能转储的最大连续文件大小之和ret
    
    // 使用双指针法遍历文件序列arr,通过移动指针来找到能转储的最大连续文件大小之和
    while (r < n) {
        // 将当前文件大小加到curr上
        curr += arr[r];
        
        // 如果curr小于等于M,更新ret为curr和ret中的较大值,右指针r向右移动一位
        if (curr <= M) {
            if (curr > ret) {
                ret = curr;
            }
            r++;
        } else {
            // 如果curr大于M,说明当前连续文件大小之和超过了SATA盘容量,需要调整边界来找到新的连续文件
            // 将左指针l指向的文件大小从curr中减去
            curr -= arr[l];
            // 左指针l向右移动一位
            l++;
        }
    }
    
    // 输出能转储的最大连续文件大小之和ret
    cout << ret << "\n";
    
    return 0; // 程序结束
}


🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

<think>我们正在解决使用atc进行模型转换时出现的Segmentation fault错误。Segmentation fault(段错误)通常是由于程序访问了非法内存区域引起的。根据引用[1]的解释,段错误是指访问的内存超出了系统所给程序的内存空间,可能是访问了不存在的内存或受系统保护的内存区域。引用[2]中直接出现了atc工具执行时的段错误信息。 解决步骤: 1. 确认环境配置: - 检查昇腾驱动和CANN工具包的版本是否匹配,并且正确安装。环境变量(如`ASCEND_TOOLKIT_HOME`)是否设置正确。引用[5]中提到了环境配置的命令,但这里主要是为了说明环境配置的重要性。 2. 检查模型文件- 确保模型文件(如ONNX、PB等)没有损坏,并且是完整的。可以尝重新生成或下载模型文件。 3. 检查输入参数: - 确保atc命令的参数正确,特别是模型路径、输出路径、soc_version等。参数错误可能导致程序内部访问异常。 4. 查看详细日志: - 尽管用户之前希望关闭控制台输出,但在调段错误时,我们需要更多的日志信息。因此,可以暂时将日志级别设置为`debug`,以便获取更多信息: ```bash atc ... --log=debug ``` 这样会输出详细的调信息,可能包含导致段错误的线索。 5. 检查核心转储(core dump): - 如果系统开启了core dump,在出现段错误时会生成core文件。我们可以使用gdb工具析core文件,定位问题发生的位置。例如: ```bash gdb /usr/local/Ascend/ascend-toolkit/latest/bin/atc.bin core.<pid> ``` 在gdb中运行`bt`命令查看堆栈跟踪,找到出错的函数调用。 6. 检查系统资源: - 段错误也可能是由于系统资源不足(如内存耗尽)导致。使用`free -h`等命令检查内存使用情况,确保有足够的内存用于模型转换。 7. 更新软件版本: - 如果当前使用的ATC工具版本较旧,可能存在已知的bug。尝更新到最新版本的CANN工具包,以修复可能的问题。 8. 简化模型: - 如果模型过于复杂,可以尝简化模型(如减少层数、减小输入尺寸等)或转换,以确定是否是模型复杂度过高导致。 9. 检查硬件兼容性: - 确认使用的soc_version参数是否正确,是否与实际的昇腾硬件版本匹配。 10. 联系技术支持: - 如果以上步骤无法解决问题,建议联系华为昇腾的技术支持,提供详细的日志和core dump文件(如果有)以便进一步析。 根据引用[3]中提到的配置问题,我们也要注意系统环境(如时间同步)是否正常,但这不是直接导致段错误的原因,因此主要关注点还是在前面的步骤。 注意:在调过程中,我们可能需要暂时关闭之前的重定向(如`> /dev/null 2>&1`),以便在控制台查看错误信息。 示例调命令: ```bash # 设置日志级别为debug,并将日志输出到文件(同时控制台也会显示,但重定向到文件方便查看) atc --model=model.onnx --output=model_om --soc_version=Ascend310 --framework=5 --log=debug 2> atc_debug.log ``` 然后检查`atc_debug.log`文件中的错误信息。 另外,引用[4]中提到了量化模型,如果模型是量化后的模型,需要确保量化过程正确,并且量化模型符合ATC的要求。 总结:Segmentation fault错误通常需要从环境配置、输入文件、参数设置、资源限制等方面进行排查,并利用调工具(如gdb)和详细日志来定位问题。</think>### 解决ATC模型转换出现Segmentation Fault错误的方法 当使用ATC工具进行模型转换时出现`Segmentation fault`错误(如引用[2]所示),通常是由于内存访问越界或系统资源问题导致。以下是系统性的排查和解决方法: --- ### 一、核心原因析(基于引用[1]) Segmentation fault的根本原因是**程序访问了非法内存区域**: 1. **越界访问**:尝读写未配的内存 2. **空指针解引用**:访问未初始化的指针 3. **栈溢出**:递归过深或大对象局部变量 4. **硬件不兼容**:指令集/内存对齐问题 5. **资源耗尽**:内存/文件句柄不足 --- ### 二、具体解决步骤 #### 1. 检查模型完整性(首要步骤) ```bash # 使用模型验证工具(如ONNX checker) python -c "import onnx; onnx.checker.check_model('your_model.onnx')" # 检查模型输入输出维度 atc --model=model.onnx --output=tmp --soc_version=Ascend310 --disable_reuse_memory=1 ``` - 修复任何模型结构错误(如未初始化张量) - 确保输入尺寸与模型匹配(参考引用[4]的量化模型要求) #### 2. 启用详细日志定位错误点 ```bash # 强制开启DEBUG日志和内存检查 export ASCEND_GLOBAL_LOG_LEVEL=3 # DEBUG级别 export ASCEND_SLOG_PRINT_TO_STDOUT=1 atc --model=model.pb --output=out --soc_version=Ascend310 --log=debug ``` - 检查日志末尾的堆栈跟踪(如引用[2]的`line 17`) - 关注`ERROR`或`WARNING`提示的算子名称 #### 3. 内存资源优化 ```bash # 增加系统交换空间(临时方案) sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 限制ATC内存使用(预防OOM) export MS_BUILD_PROCESS_NUM=1 # 限制并行线程 export MAX_COMPILE_CORE_NUMBER=1 ``` #### 4. 检查硬件兼容性 ```bash # 确认soc_version参数正确 npu-smi info # 查看芯片型号 atc --soc_version=Ascend310 # 需与实际一致 # 更新驱动和固件 sudo apt-get install nvidia-driver-510 # NVIDIA示例 ascend-update # 昇腾专用更新工具 ``` #### 5. 高级调手段 ```c // 使用GDB捕获核心转储 gdb --args atc.bin --model=model.pb (gdb) run (gdb) bt full // 发生crash后执行 ``` - 析堆栈帧中的函数调用顺序 - 检查指针变量值是否为`0x0`(空指针) --- ### 三、预防措施 1. **模型预处理**: - 使用`onnx-simplifier`简化计算图 ```bash python -m onnxsim input_model.onnx output_model.onnx ``` 2. **资源监控**: ```bash watch -n 1 "free -h && ls /dev/ | grep nvidia" # 实时监控 ``` 3. **环境隔离**: ```bash # 使用Docker容器(如引用[5]) docker run --gpus all -it ascend/toolkit:5.1 bash ``` --- ### 四、典型错误场景对照表 | 错误现象 | 可能原因 | 解决方案 | |---------|---------|---------| | `Segmentation fault at convolution_op` | 输入尺寸不匹配 | 检查input_shape参数 | | 转换大模型时随崩溃 | 内存碎片化 | 添加`--disable_reuse_memory=1` | | 特定算子报错 | 算子兼容性问题 | 使用`--op_select_implmode`降级 | | 日志中出现`mmap failed` | 虚拟内存不足 | 增加`/proc/sys/vm/overcommit_memory`值 | > 如果问题仍未解决,建议收集以下信息联系华为技术支持: > 1. `npu-smi info`输出 > 2. ATC日志文件(`~/ascend/log/plog`) > 3. 核心转储文件(需提前执行`ulimit -c unlimited`)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值