HDFql 从 std::vector 迭代填充数据集
HDFql Filling Dataset Iteratively from std::vector
我正在尝试使用 HDFql 迭代地在 HDF5 文件中填充数据集。我所说的迭代是指我的模拟器偶尔会进行更新,我希望将更多数据(包含在 std::vector
中)转储到我的数据集中。奇怪的是,在 'iterations' 之后出现了一些问题,我的数据集开始只填满零。
幸运的是,这个错误也发生在一个最小的例子中,似乎可以用下面的代码重现:
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE GROUP data");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(UNLIMITED)");
HDFql::execute("CLOSE FILE");
std::stringstream ss;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 500);
std::uniform_int_distribution<> dist_len(300, 1000);
for(int i=0; i<500; i++)
{
const int num_values = dist_len(eng);
std::vector<uint16_t> vals;
for(int i=0; i<num_values; i++)
{
const int value = dist_vals(eng);
vals.push_back(value);
}
HDFql::execute("USE FILE /tmp/test_random.h5");
ss << "ALTER DIMENSION data/vals TO +" << vals.size();
HDFql::execute(ss.str().c_str()); ss.str("");
ss << "INSERT INTO data/vals(-" << vals.size() << ":1:1:" << vals.size()
<< ") VALUES FROM MEMORY "
<< HDFql::variableTransientRegister(vals.data());
HDFql::execute(ss.str().c_str()); ss.str("");
HDFql::execute("CLOSE FILE");
}
}
此代码 运行s 500 'iterations',每次用随机数据填充数据向量。在我最新的 运行 中,最终输出的 hdf 文件中超出数据单元 4065 的所有内容都只是零。
所以我的问题是:我在这里做错了什么?
非常感谢!
编辑
经过进一步的实验,我得出的结论是这可能是 HDFql 中的一个错误。查看以下示例:
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(0 TO UNLIMITED)");
std::stringstream ss;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 450);
std::uniform_int_distribution<> dist_len(100, 300);
int total_added = 0;
for(int i=0; i<5000; i++)
{
const int num_values = 1024; //dist_len(eng);
std::vector<uint16_t> vals;
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.push_back(value);
}
long long dim=0;
ss << "SHOW DIMENSION data/vals INTO MEMORY " << HDFql::variableTransientRegister(&dim);
HDFql::execute(ss.str().c_str()); ss.str("");
ss << "ALTER DIMENSION data/vals TO +" << vals.size();
HDFql::execute(ss.str().c_str()); ss.str("");
ss << "INSERT INTO data/vals(-" << vals.size() << ":1:1:" << vals.size()
<< ") VALUES FROM MEMORY "
<< HDFql::variableTransientRegister(vals.data());
HDFql::execute(ss.str().c_str()); ss.str("");
total_added += vals.size();
std::cout << i << ": "<< ss.str() << ": dim = " << dim
<< " : added = " << vals.size() << " (total="
<< total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
此代码将数据大小保持在 1024 (num_values = 1024;
),应该可以正常工作。但是,如果将其更改为 1025,则会出现错误并通过控制台输出证明:
....
235: : dim = 240875 : added = 1025 (total=241900)
236: : dim = 241900 : added = 1025 (total=242925)
237: : dim = 0 : added = 1025 (total=243950)
238: : dim = 0 : added = 1025 (total=244975)
239: : dim = 0 : added = 1025 (total=246000)
....
表明在第 470 次迭代时出现问题,因为数据集的维度显然不为零。
奇怪的是,这并不能解释为什么我在原始示例中遇到这个问题,因为数据数组的大小上限为 500。
您在外循环和内循环 for
中都使用了变量 i
,这是错误的。另外,作为建议,您发布的代码片段可以通过以下方式进行优化:
不需要像创建数据集data/vals
那样创建组data
,HDFql创建data
作为一个组(如果它不存在)并且vals
作为数据集。
无需在循环内打开和关闭文件/tmp/test_random.h5
(因为这会降低性能);只需在代码开头打开文件并在代码末尾关闭它。
代码如下 corrected/refactored:
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
HDFql::execute("CREATE TRUNCATE AND USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(0 TO UNLIMITED)");
std::stringstream ss;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 500);
std::uniform_int_distribution<> dist_len(300, 1000);
for(int i=0; i<500; i++)
{
const int num_values = dist_len(eng);
std::vector<uint16_t> vals;
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.push_back(value);
}
ss.str("");
ss << "ALTER DIMENSION data/vals TO +" << vals.size();
HDFql::execute(ss);
ss.str("");
ss << "INSERT INTO data/vals(-" << vals.size() << ":1:1:" << vals.size()
<< ") VALUES FROM MEMORY "
<< HDFql::variableTransientRegister(vals);
HDFql::execute(ss);
}
HDFql::execute("CLOSE FILE");
}
回复您上面的编辑,将 num_values
设置为 1025
的数据集维度扩展没有问题。
这是我用来测试这个的代码片段:
#include <iostream>
#include "HDFql.hpp"
int main(int argc, char *argv[])
{
char script[1024];
int total_added = 0;
int num_values = 1025;
HDFql::execute("CREATE TRUNCATE AND USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(0 TO UNLIMITED)");
for(int i = 0; i < 5000; i++)
{
long long dim = 0;
sprintf(script, "SHOW DIMENSION data/vals INTO MEMORY %d", HDFql::variableTransientRegister(&dim));
HDFql::execute(script);
sprintf(script, "ALTER DIMENSION data/vals TO +%d", num_values);
HDFql::execute(script);
total_added += num_values;
std::cout << i << ": " << ": dim = " << dim << " : added = " << num_values << " (total=" << total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
所以我找出了问题所在 - 在下面,第一个示例有效而第二个示例无效:
有效
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
int total_added = 0;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 450);
std::uniform_int_distribution<> dist_len(100, 300);
const int fixed_buffer_size = 10000;
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS INT(0 TO UNLIMITED)");
for(int i = 0; i < 5000; i++)
{
const int num_values = dist_len(eng);
std::vector<int> vals(fixed_buffer_size);
long long dim = 0;
sprintf(script, "SHOW DIMENSION data/vals INTO MEMORY %d", HDFql::variableTransientRegister(&dim));
HDFql::execute(script);
sprintf(script, "ALTER DIMENSION data/vals TO +%d", num_values);
HDFql::execute(script);
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.at(j) = value;
}
sprintf(script, "INSERT INTO data/vals(-%d:1:1:%d) VALUES FROM MEMORY %d", num_values, num_values, HDFql::variableTransientRegister(vals.data()));
HDFql::execute(script);
HDFql::execute("FLUSH");
total_added += num_values;
std::cout << i << ": " << ": dim = " << dim << " : added = " << num_values << " (total=" << total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
失败
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
int total_added = 0;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 450);
std::uniform_int_distribution<> dist_len(100, 300);
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS INT(0 TO UNLIMITED)");
for(int i = 0; i < 5000; i++)
{
const int num_values = dist_len(eng);
std::vector<int> vals(num_values);
long long dim = 0;
sprintf(script, "SHOW DIMENSION data/vals INTO MEMORY %d", HDFql::variableTransientRegister(&dim));
HDFql::execute(script);
sprintf(script, "ALTER DIMENSION data/vals TO +%d", num_values);
HDFql::execute(script);
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.at(j) = value;
}
sprintf(script, "INSERT INTO data/vals(-%d:1:1:%d) VALUES FROM MEMORY %d", num_values, num_values, HDFql::variableTransientRegister(vals.data()));
HDFql::execute(script);
HDFql::execute("FLUSH");
total_added += num_values;
std::cout << i << ": " << ": dim = " << dim << " : added = " << num_values << " (total=" << total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
两者之间的仅区别在于,第一个数据缓冲区的大小vals
是固定的,第二个数据缓冲区大小是创建的动态地和随机地。
我不明白为什么会出现此错误,因为在 c++ 中 std::vector
是 supposed 使基础数据在内存中连续存在并与 C 数组和指针魔术完全兼容。但很明显,编译器在每个示例中都做了不同的事情。无论如何,我希望这可以帮助其他人解决这个问题 - 解决方案是使用固定大小的数据缓冲区。
我正在尝试使用 HDFql 迭代地在 HDF5 文件中填充数据集。我所说的迭代是指我的模拟器偶尔会进行更新,我希望将更多数据(包含在 std::vector
中)转储到我的数据集中。奇怪的是,在 'iterations' 之后出现了一些问题,我的数据集开始只填满零。
幸运的是,这个错误也发生在一个最小的例子中,似乎可以用下面的代码重现:
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE GROUP data");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(UNLIMITED)");
HDFql::execute("CLOSE FILE");
std::stringstream ss;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 500);
std::uniform_int_distribution<> dist_len(300, 1000);
for(int i=0; i<500; i++)
{
const int num_values = dist_len(eng);
std::vector<uint16_t> vals;
for(int i=0; i<num_values; i++)
{
const int value = dist_vals(eng);
vals.push_back(value);
}
HDFql::execute("USE FILE /tmp/test_random.h5");
ss << "ALTER DIMENSION data/vals TO +" << vals.size();
HDFql::execute(ss.str().c_str()); ss.str("");
ss << "INSERT INTO data/vals(-" << vals.size() << ":1:1:" << vals.size()
<< ") VALUES FROM MEMORY "
<< HDFql::variableTransientRegister(vals.data());
HDFql::execute(ss.str().c_str()); ss.str("");
HDFql::execute("CLOSE FILE");
}
}
此代码 运行s 500 'iterations',每次用随机数据填充数据向量。在我最新的 运行 中,最终输出的 hdf 文件中超出数据单元 4065 的所有内容都只是零。
所以我的问题是:我在这里做错了什么? 非常感谢!
编辑
经过进一步的实验,我得出的结论是这可能是 HDFql 中的一个错误。查看以下示例:
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(0 TO UNLIMITED)");
std::stringstream ss;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 450);
std::uniform_int_distribution<> dist_len(100, 300);
int total_added = 0;
for(int i=0; i<5000; i++)
{
const int num_values = 1024; //dist_len(eng);
std::vector<uint16_t> vals;
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.push_back(value);
}
long long dim=0;
ss << "SHOW DIMENSION data/vals INTO MEMORY " << HDFql::variableTransientRegister(&dim);
HDFql::execute(ss.str().c_str()); ss.str("");
ss << "ALTER DIMENSION data/vals TO +" << vals.size();
HDFql::execute(ss.str().c_str()); ss.str("");
ss << "INSERT INTO data/vals(-" << vals.size() << ":1:1:" << vals.size()
<< ") VALUES FROM MEMORY "
<< HDFql::variableTransientRegister(vals.data());
HDFql::execute(ss.str().c_str()); ss.str("");
total_added += vals.size();
std::cout << i << ": "<< ss.str() << ": dim = " << dim
<< " : added = " << vals.size() << " (total="
<< total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
此代码将数据大小保持在 1024 (num_values = 1024;
),应该可以正常工作。但是,如果将其更改为 1025,则会出现错误并通过控制台输出证明:
....
235: : dim = 240875 : added = 1025 (total=241900)
236: : dim = 241900 : added = 1025 (total=242925)
237: : dim = 0 : added = 1025 (total=243950)
238: : dim = 0 : added = 1025 (total=244975)
239: : dim = 0 : added = 1025 (total=246000)
....
表明在第 470 次迭代时出现问题,因为数据集的维度显然不为零。
奇怪的是,这并不能解释为什么我在原始示例中遇到这个问题,因为数据数组的大小上限为 500。
您在外循环和内循环 for
中都使用了变量 i
,这是错误的。另外,作为建议,您发布的代码片段可以通过以下方式进行优化:
不需要像创建数据集
data/vals
那样创建组data
,HDFql创建data
作为一个组(如果它不存在)并且vals
作为数据集。无需在循环内打开和关闭文件
/tmp/test_random.h5
(因为这会降低性能);只需在代码开头打开文件并在代码末尾关闭它。
代码如下 corrected/refactored:
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
HDFql::execute("CREATE TRUNCATE AND USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(0 TO UNLIMITED)");
std::stringstream ss;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 500);
std::uniform_int_distribution<> dist_len(300, 1000);
for(int i=0; i<500; i++)
{
const int num_values = dist_len(eng);
std::vector<uint16_t> vals;
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.push_back(value);
}
ss.str("");
ss << "ALTER DIMENSION data/vals TO +" << vals.size();
HDFql::execute(ss);
ss.str("");
ss << "INSERT INTO data/vals(-" << vals.size() << ":1:1:" << vals.size()
<< ") VALUES FROM MEMORY "
<< HDFql::variableTransientRegister(vals);
HDFql::execute(ss);
}
HDFql::execute("CLOSE FILE");
}
回复您上面的编辑,将 num_values
设置为 1025
的数据集维度扩展没有问题。
这是我用来测试这个的代码片段:
#include <iostream>
#include "HDFql.hpp"
int main(int argc, char *argv[])
{
char script[1024];
int total_added = 0;
int num_values = 1025;
HDFql::execute("CREATE TRUNCATE AND USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS SMALLINT(0 TO UNLIMITED)");
for(int i = 0; i < 5000; i++)
{
long long dim = 0;
sprintf(script, "SHOW DIMENSION data/vals INTO MEMORY %d", HDFql::variableTransientRegister(&dim));
HDFql::execute(script);
sprintf(script, "ALTER DIMENSION data/vals TO +%d", num_values);
HDFql::execute(script);
total_added += num_values;
std::cout << i << ": " << ": dim = " << dim << " : added = " << num_values << " (total=" << total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
所以我找出了问题所在 - 在下面,第一个示例有效而第二个示例无效:
有效
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
int total_added = 0;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 450);
std::uniform_int_distribution<> dist_len(100, 300);
const int fixed_buffer_size = 10000;
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS INT(0 TO UNLIMITED)");
for(int i = 0; i < 5000; i++)
{
const int num_values = dist_len(eng);
std::vector<int> vals(fixed_buffer_size);
long long dim = 0;
sprintf(script, "SHOW DIMENSION data/vals INTO MEMORY %d", HDFql::variableTransientRegister(&dim));
HDFql::execute(script);
sprintf(script, "ALTER DIMENSION data/vals TO +%d", num_values);
HDFql::execute(script);
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.at(j) = value;
}
sprintf(script, "INSERT INTO data/vals(-%d:1:1:%d) VALUES FROM MEMORY %d", num_values, num_values, HDFql::variableTransientRegister(vals.data()));
HDFql::execute(script);
HDFql::execute("FLUSH");
total_added += num_values;
std::cout << i << ": " << ": dim = " << dim << " : added = " << num_values << " (total=" << total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
失败
#include <stdio.h>
#include <random>
#include <HDFql.hpp>
int main (int argc, const char * argv[]) {
int total_added = 0;
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> dist_vals(0, 450);
std::uniform_int_distribution<> dist_len(100, 300);
HDFql::execute("CREATE TRUNCATE FILE /tmp/test_random.h5");
HDFql::execute("USE FILE /tmp/test_random.h5");
HDFql::execute("CREATE CHUNKED DATASET data/vals AS INT(0 TO UNLIMITED)");
for(int i = 0; i < 5000; i++)
{
const int num_values = dist_len(eng);
std::vector<int> vals(num_values);
long long dim = 0;
sprintf(script, "SHOW DIMENSION data/vals INTO MEMORY %d", HDFql::variableTransientRegister(&dim));
HDFql::execute(script);
sprintf(script, "ALTER DIMENSION data/vals TO +%d", num_values);
HDFql::execute(script);
for(int j=0; j<num_values; j++)
{
const int value = dist_vals(eng);
vals.at(j) = value;
}
sprintf(script, "INSERT INTO data/vals(-%d:1:1:%d) VALUES FROM MEMORY %d", num_values, num_values, HDFql::variableTransientRegister(vals.data()));
HDFql::execute(script);
HDFql::execute("FLUSH");
total_added += num_values;
std::cout << i << ": " << ": dim = " << dim << " : added = " << num_values << " (total=" << total_added << ")" << std::endl;
}
HDFql::execute("CLOSE FILE");
}
两者之间的仅区别在于,第一个数据缓冲区的大小vals
是固定的,第二个数据缓冲区大小是创建的动态地和随机地。
我不明白为什么会出现此错误,因为在 c++ 中 std::vector
是 supposed 使基础数据在内存中连续存在并与 C 数组和指针魔术完全兼容。但很明显,编译器在每个示例中都做了不同的事情。无论如何,我希望这可以帮助其他人解决这个问题 - 解决方案是使用固定大小的数据缓冲区。