| 204 | } |
| 205 | |
| 206 | void ParameterFileIOImpl<DeviceTypes::kCPU, ModelFileVersion::kV1>::write(const ParameterFile::ptr_t& parameter_file, |
| 207 | const std::string& file_path) { |
| 208 | std::ofstream out_file(file_path, std::ios::binary); |
| 209 | if (!out_file.is_open()) { MLLM_ERROR_EXIT(ExitCode::kIOError, "Failed to open file for writing: {}", file_path); } |
| 210 | |
| 211 | size_t header_size = sizeof(ModelFileV1Descriptor); |
| 212 | size_t param_desc_total_size = 0; |
| 213 | |
| 214 | // Calculate total size of the descriptor section |
| 215 | for (const auto& pair : *parameter_file) { |
| 216 | const auto& tensor = pair.second; |
| 217 | param_desc_total_size += sizeof(uint32_t); // name length |
| 218 | param_desc_total_size += tensor.impl()->storage()->name_.size(); // name string |
| 219 | param_desc_total_size += sizeof(uint64_t); // data length |
| 220 | param_desc_total_size += sizeof(uint64_t); // offset |
| 221 | param_desc_total_size += sizeof(int32_t); // data type |
| 222 | } |
| 223 | |
| 224 | // Write header: parameter_desc_offset is now the SIZE of the descriptor section |
| 225 | ModelFileV1Descriptor header{}; |
| 226 | header.magic_number = MLLM_MODEL_FILE_V1_MAGIC_NUMBER; |
| 227 | header.parameter_desc_offset = param_desc_total_size; // FIXED: size of descriptors (without header) |
| 228 | out_file.write(reinterpret_cast<const char*>(&header), sizeof(header)); |
| 229 | |
| 230 | // Write parameter descriptors and calculate data offsets |
| 231 | uint64_t current_data_offset = header_size + param_desc_total_size; // Absolute offset for tensor data |
| 232 | for (const auto& pair : *parameter_file) { |
| 233 | const auto& name = pair.first; |
| 234 | const auto& tensor = pair.second; |
| 235 | |
| 236 | // Name length |
| 237 | uint32_t name_len = name.size(); |
| 238 | out_file.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len)); |
| 239 | |
| 240 | // Name |
| 241 | out_file.write(name.c_str(), name_len); |
| 242 | |
| 243 | // Data length (bytes) |
| 244 | uint64_t data_len = tensor.bytes(); |
| 245 | out_file.write(reinterpret_cast<const char*>(&data_len), sizeof(data_len)); |
| 246 | |
| 247 | // Offset (absolute from file start) |
| 248 | out_file.write(reinterpret_cast<const char*>(¤t_data_offset), sizeof(current_data_offset)); |
| 249 | current_data_offset += data_len; |
| 250 | |
| 251 | // Data type |
| 252 | int32_t dtype = static_cast<int32_t>(tensor.dtype()); |
| 253 | out_file.write(reinterpret_cast<const char*>(&dtype), sizeof(dtype)); |
| 254 | } |
| 255 | |
| 256 | // Write tensor data |
| 257 | for (const auto& pair : *parameter_file) { |
| 258 | const auto& tensor = pair.second; |
| 259 | size_t data_size = tensor.bytes(); |
| 260 | out_file.write(reinterpret_cast<const char*>(tensor.ptr<uint8_t>()), data_size); |
| 261 | } |
| 262 | |
| 263 | out_file.close(); |
no test coverage detected