26 typedef std::chrono::high_resolution_clock 
clockType;
 
   28                           clockType::duration t) {
 
   30     stream << std::chrono::duration_cast<std::chrono::duration<double>>(t).count();
 
   39     std::list<std::pair<std::string, std::string>> 
parameters;
 
   40     std::list<std::pair<options::base&, std::string>> 
options;
 
   58     static std::map<std::string, baseTest*>& 
getList() {
 
   59         static std::remove_reference<decltype(
getList())>::type list;
 
   69              const std::string& aDescription,
 
   71              const decltype(
options)& aOptions = {}):
 
   84             for (
const auto& opt : 
options) {
 
  104     virtual void execute(
const std::vector<std::string>& remainingOptions) = 0;
 
  107         auto bytesToWrite = data.size();
 
  108         auto ptr = data.data();
 
  109         while (bytesToWrite > 0) {
 
  110             auto result = write(fd, ptr, bytesToWrite);
 
  112                 if (errno == EINTR) {
 
  118                 bytesToWrite -= result;
 
  123         auto bytesToRead = data.size();
 
  124         auto ptr = 
const_cast<char*
>(data.data()); 
 
  125         while (bytesToRead > 0) {
 
  126             auto result = read(fd, ptr, bytesToRead);
 
  127             if (result == -1 && errno == EINTR) {
 
  131             bytesToRead -= result;
 
  134     void Execute(
const std::vector<std::string>& remainingOptions) {
 
  141             auto fd = 
throwcall::badval(open(
"/dev/urandom", O_RDONLY), -1, 
"open /dev/urandom");
 
  149             for (
unsigned i = 0; 
true; i++) {
 
  150                 auto number = std::to_string(i);
 
  166             struct stat statData;
 
  168             content.resize(statData.st_size);
 
  172         std::vector<clockType::duration> times;
 
  175         for (
unsigned i = 0; i < 
repeat; i++) {
 
  177                 auto now = std::chrono::system_clock::now();
 
  178                 auto seconds = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
 
  179                 auto divresult = std::div(seconds, 
syncus);
 
  180                 auto then = std::chrono::system_clock::time_point(std::chrono::microseconds(divresult.quot * 
syncus + 
syncus + (i % 
syncus) * 
skewus));
 
  181                 std::this_thread::sleep_until(then);
 
  183             auto tStart = clockType::now();
 
  185             auto tStop = clockType::now();
 
  186             auto dt = tStop - tStart;
 
  191                 std::cout << 
"removing " << file << 
"\n";
 
  197             std::cout << 
"took " << times.at(0) << 
"s\n";
 
  199             auto minMax = std::minmax_element(times.begin(), times.end());
 
  200             std::cout << 
"minimum time: " << *(minMax.first) << 
"s\n";
 
  201             std::cout << 
"maximum time: " << *(minMax.second) << 
"s\n";
 
  202             auto sum = std::accumulate(times.begin(), times.end(), clockType::duration::zero());
 
  203             auto mean = std::chrono::duration_cast<std::chrono::duration<double>>(sum).count() / 
repeat;
 
  204             std::cout << 
"average time: " << mean << 
"s\n";
 
  205             std::map<double, unsigned long> histogram;
 
  207             auto range = std::chrono::duration_cast<std::chrono::duration<double>>(*(minMax.second) - * (minMax.first)).count();
 
  208             auto lowBorder = std::chrono::duration_cast<std::chrono::duration<double>>(*(minMax.first)).count();
 
  209             if (mean < lowBorder + range / 10) { 
 
  210                 auto border = lowBorder;
 
  211                 histogram[border] = 0;
 
  212                 auto factor = std::pow(std::chrono::duration_cast<std::chrono::duration<double>>(*(minMax.second)).count() / lowBorder,
 
  214                 for (
unsigned i = 0; i < bins; i++) {
 
  216                     histogram[border] = 0;
 
  219                 lowBorder -= range / (2 * bins);
 
  223                 for (
unsigned i = 0; i < bins + 1; i++) {
 
  224                     histogram[lowBorder + i * range / bins] = 0;
 
  227             for (
auto t : times) {
 
  228                 auto bin = histogram.begin();
 
  229                 for (
auto testBin = bin; testBin != histogram.end(); ++testBin) {
 
  230                     if (std::chrono::duration_cast<std::chrono::duration<double>>(t).count() < testBin->first) {
 
  237             for (
auto& bin : histogram) {
 
  238                 std::cout << bin.first << 
": " << bin.second << 
"\n";
 
  245         "repeat this many times", 1);
 
  247                                         "remove created files after running tests");
 
  249                                         "get content from /dev/urandom");
 
  251         "set content to decimal ascenfing numbers");
 
  253         "name of file for content", 
"");
 
  255                                        "size of content string", 0);
 
  257         "number of blocks to write", 1);
 
  260         "content of file", 
"blabla");
 
  262                                          "use O_TRUNC on open()");
 
  264         "characteristic test time (s)",
 
  265         std::chrono::seconds(0));
 
  267         "sync start times to sync microseconds", 0);
 
  269         "skew start times by skew microseconds", 0);
 
  274                             "create a file via O_TMPFILE", {
 
  275         {
"dir", 
"directory to create the file in"},
 
  276         {
"file", 
"path to the file to create"}
 
  278     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  279         auto dir = remainingOptions.at(0);
 
  280         auto file = remainingOptions.at(1);
 
  281         auto result = unlink(file.c_str());
 
  282         if (result == -1 && errno != ENOENT) {
 
  286                                     "open anonymous file in ", dir);
 
  288         std::string path(
"/proc/self/fd/");
 
  289         path += std::to_string(fd);
 
  290         throwcall::good0(linkat(AT_FDCWD, path.c_str(), AT_FDCWD, file.c_str(), AT_SYMLINK_FOLLOW),
 
  291                          "link ", path, 
" to ", file);
 
  301                              "simulate the way vim writes a file", {
 
  302         {
"file", 
"path to the file to create" 
  306     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  307         auto file = remainingOptions.at(0);
 
  308         std::string tildeFile(file);
 
  311         unlink(tildeFile.c_str());
 
  312         if (stat(file.c_str(), &buf) != 0) {
 
  313             if (errno == ENOENT) {
 
  314                 auto fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644), -1,
 
  323                          "rename ", file, 
" to ", tildeFile);
 
  324         auto fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644), -1,
 
  339                              "open file for reading and keep open", {
 
  340         {
"file", 
"path to file" 
  343     {{
time, 
"keep open this long"}}) {};
 
  344     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  345         auto file = remainingOptions.at(0);
 
  347         std::this_thread::sleep_for(
time);
 
  357                                  "create a file and append blocks to it, changing the first one.", {
 
  358         {
"file", 
"path to file" 
  361     {{
time, 
"wait this long between writes"}}) {};
 
  362     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  363         auto file = remainingOptions.at(0);
 
  364         for (
unsigned i = 0; i < 
blocks; i++) {
 
  366                 std::this_thread::sleep_for(
time);
 
  368             auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_WRONLY, 0744), -1, 
"open ", file);
 
  384                                 "create a file and write into it", {
 
  385         {
"file", 
"path to file" 
  388         {{
time, 
"wait this long between writes"},
 
  389          {
truncate, 
"use O_TRUNC on open()"}}) {};
 
  390     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  391         auto file = remainingOptions.at(0);
 
  392         auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_WRONLY | ( 
truncate ? O_TRUNC : 0), 0744), -1, 
"open ", file);
 
  393         for (
unsigned i = 0; i < 
blocks; i++) {
 
  395                 std::this_thread::sleep_for(
time);
 
  409                                 "create a file and write into it like cp does", {
 
  410         {
"file", 
"path to file" 
  413     {{
time, 
"wait this long between writes"}}) {};
 
  414     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  415         auto file = remainingOptions.at(0);
 
  416         auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_WRONLY | O_EXCL, 0700), -1, 
"open ", file);
 
  417         for (
unsigned i = 0; i < 
blocks; i++) {
 
  419                 std::this_thread::sleep_for(
time);
 
  434                                 "create a file with O_DIRECT and write into it", {
 
  435         {
"file", 
"path to file" 
  438     {{
time, 
"wait this long between writes"}}) {};
 
  439     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  440         auto file = remainingOptions.at(0);
 
  443                                              PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
 
  446                                         "mmap ", 
content.size(), 
" bytes anonymously");
 
  448         auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_WRONLY | O_DIRECT, 0744), -1, 
"open ", file);
 
  449         for (
unsigned i = 0; i < 
blocks; i++) {
 
  451                 std::this_thread::sleep_for(
time);
 
  465                               "create a file, mmap() it and write into it", {
 
  466         {
"file", 
"path to file" 
  469     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  470         auto file = remainingOptions.at(0);
 
  471         auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_RDWR, 0744), -1, 
"open ", file);
 
  473         throwcall::good0(ftruncate(fd, mapSize), 
"truncate to ", mapSize, 
" bytes");
 
  475                                           PROT_WRITE, MAP_SHARED,
 
  478                                      "mmap ", 
content.size(), 
" bytes from ", file);
 
  479         for (
unsigned i = 0; i < 
blocks; i++) {
 
  492                                 "create a sparse file, data (hole data){blocks}", {
 
  493         {
"file", 
"path to file" 
  496     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  497         auto file = remainingOptions.at(0);
 
  498         auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_WRONLY, 0744), -1, 
"open ", file);
 
  500         for (
unsigned i = 0; i < 
blocks; i++) {
 
  502                               "lseek in ", file, 
" for ", 
content.size(), 
" bytes");
 
  514                                  "create a sparse file, hole (data hole){blocks}", {
 
  515         {
"file", 
"path to file" 
  518     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  519         auto file = remainingOptions.at(0);
 
  520         auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_WRONLY, 0744), -1, 
"open ", file);
 
  522                           "lseek in ", file, 
" for ", 
content.size(), 
" bytes");
 
  523         for (
unsigned i = 0; i < 
blocks; i++) {
 
  527                               "lseek in ", file, 
" for ", 
content.size(), 
" bytes");
 
  540                                     "find minimum hole size", {
 
  541         {
"file", 
"path to file" 
  544     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  545         auto file = remainingOptions.at(0);
 
  546         auto fd = 
throwcall::badval(open(file.c_str(), O_CREAT | O_WRONLY, 0744), -1, 
"open ", file);
 
  549         auto testSize = statbuf.st_blksize;
 
  550         while (testSize > 0) {
 
  552             fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_TRUNC, 0744), -1, 
"open ", file);
 
  553             throwcall::badval(lseek(fd, testSize, SEEK_SET), -1, 
"seek ", testSize, 
" in ", file);
 
  558             auto dataPos = 
throwcall::badval(lseek(fd, 0, SEEK_DATA), -1, 
"seek data in ", file);
 
  559             if (dataPos != testSize) {
 
  562             std::cout << testSize << 
" bytes hole size worked\n";
 
  573                                "append a hole to an existing file", {
 
  574         {
"file", 
"path to file" 
  577     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  578         auto file = remainingOptions.at(0);
 
  579         auto fd = 
throwcall::badval(open(file.c_str(), O_WRONLY, 0744), -1, 
"open ", file);
 
  580         auto oldFileEnd = 
throwcall::badval(lseek(fd, 0, SEEK_END), -1, 
"seek end of ", file);
 
  592                                        "create, unlink, re-create a file", {
 
  593         {
"file", 
"path to file" 
  596     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  597         auto file = remainingOptions.at(0);
 
  598         auto fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0744), -1, 
"open ", file);
 
  603         fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0744), -1, 
"open ", file);
 
  615                                   "close, move, update a file", {
 
  616         {
"file", 
"path to file" 
  619     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  620         auto file = remainingOptions.at(0);
 
  621         std::string movedFile(file);
 
  622         movedFile += 
".moved";
 
  623         auto fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0744), -1, 
"open ", file);
 
  627                          "rename ", file, 
" to ", movedFile);
 
  628         struct timespec times[2] = {{0, UTIME_OMIT}, {0, UTIME_NOW}};
 
  630                          "change mtime of ", file);
 
  639                                       "create, unlink, update a file", {
 
  640         {
"file", 
"path to file" 
  643     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  644         auto file = remainingOptions.at(0);
 
  645         auto fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0744), -1, 
"open ", file);
 
  656                                "read file and compare to content", {
 
  657         {
"file", 
"path to file" 
  660     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  661         auto file = remainingOptions.at(0);
 
  663         std::string data(
content.size(), 
'\0');
 
  665         if (data.compare(
content) != 0) {
 
  666             std::cout << 
"difference betwen content and file found\n";
 
  676                              "read file via mmap() and compare to content", {
 
  677         {
"file", 
"path to file" 
  680     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  681         auto file = remainingOptions.at(0);
 
  684                                           PROT_READ, MAP_PRIVATE | MAP_POPULATE,
 
  687                                      "mmap ", 
content.size(), 
" bytes from ", file);
 
  688         auto data = 
static_cast<const char *
>(map);
 
  690             std::cout << 
"difference betwen content and file found\n";
 
  702                                    "truncate existing file to it;s size", {
 
  703         {
"file", 
"path to file" 
  706     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  707         auto file = remainingOptions.at(0);
 
  711         throwcall::good0(ftruncate(fd, statbuf.st_size), 
"truncate ", file, 
" to ", statbuf.st_size, 
" bytes");
 
  718 class gpfsPrealloc: 
public baseTest {
 
  720     gpfsPrealloc(): 
baseTest(
"gpfsPrealloc",
 
  721                                  "write a file with gpfsRealloc", {
 
  722         {
"file", 
"path to file" 
  725     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  726         auto file = remainingOptions.at(0);
 
  727         auto fd = 
throwcall::badval(open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0744), -1, 
"open ", file);
 
  729                          "gpfs_prealloc ", content.size(), 
" bytes for ", file);
 
  734 static gpfsPrealloc gpfsPreallocInstance;
 
  740                                  "write files with ugly names", {
 
  741         {
"dir", 
"directory to create the files in" 
  744     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  745         auto dir = remainingOptions.at(0);
 
  746         auto dirfd = 
throwcall::badval(open(dir.c_str(),O_PATH | O_DIRECTORY),-1,
"can't open ",dir);
 
  747         std::list<std::string> names{
"name with spaces",
 
  748                                      "name\nwith\nnewlines",
 
  749                                      "name\rwith\rreturns",
 
  750                                      "name\r\nwith\r\nCRLF",
 
  751                                      "name_with_\033[91mred\033[0m_part",
 
  752                                      "name_with_\xe2\x80\xadleft-to-right\xe2\x80\x8e_part",
 
  753                                      "name_with_\xe2\x82\xac_euro",
 
  754                                      "name_with_ɄɳɨȻʘΔε_unicode",
 
  755                                      "name_with_🤔💩☢_emojis",
 
  756                                      "name_with_䭫顙_more_unicode" 
  759             std::list<std::pair<std::string,unsigned char>> ControlChars{
 
  760                 {
"SOH", 001},   {
"STX", 002},   {
"ETX", 003},   {
"EOT", 004},
 
  761                                 {
"ENQ", 005},   {
"ACK", 006},
 
  789             for (
const auto& cc: ControlChars) {
 
  790                 std::string ugly(
"name_with_");
 
  791                 ugly.push_back(cc.second);
 
  793                 ugly+=std::to_string(cc.second);
 
  796                 names.push_back(ugly);
 
  800             std::vector<std::pair<unsigned char, unsigned char>> ranges{{32,46},{58,63},{91,96},{123,126}};
 
  801             for (
const auto& range: ranges) { 
 
  802                 for (
unsigned char c=range.first; c<=range.second; c++) {
 
  803                     std::string ugly(
"name_with_");
 
  806                     ugly+=std::to_string(c);
 
  807                     names.push_back(ugly);
 
  811         for (
unsigned char c=128; c!=0; c++) {
 
  812             std::string ugly(
"name_with_");
 
  815             ugly+=std::to_string(c);
 
  816             names.push_back(ugly);
 
  819             auto nameMax = 
throwcall::badval(fpathconf(dirfd,_PC_NAME_MAX),-1,
"can't get max name length");
 
  820             auto ugly = std::to_string(nameMax);
 
  821             ugly.resize(nameMax,
'b');
 
  822             names.push_back(ugly);
 
  825         for (
const auto& ugly: names) {
 
  826             std::string file(dir);
 
  829             auto fd = openat(dirfd,ugly.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0744);
 
  830             if (fd == -1 && errno == EINVAL) {
 
  831                 std::cerr << 
"illegal file name \" << ugly << \" tried: ";
 
  832                 for (
auto c : ugly) {
 
  833                     std::cerr << std::hex << std::setw(2) << c;
 
  835                 std::cerr << std::dec << 
"\n";
 
  851                                  "write files in paths with ugly names", {
 
  852         {
"dir", 
"directory to create the paths in" 
  855     void execute(
const std::vector<std::string>& remainingOptions)
 override {
 
  856         auto dir = remainingOptions.at(0);
 
  857         auto dirfd = 
throwcall::badval(open(dir.c_str(),O_PATH | O_DIRECTORY),-1,
"can't open ",dir);
 
  858         std::list<std::string> names{
"path with spaces",
 
  859                                      "path\nwith\nnewlines",
 
  860                                      "path\rwith\rreturns",
 
  861                                      "path\r\nwith\r\nCRLF",
 
  862                                      "path_with_\033[91mred\033[0m_part",
 
  863                                      "path_with_\xe2\x80\xadleft-to-right\xe2\x80\x8e_part",
 
  864                                      "path_with_\xe2\x82\xac_euro",
 
  865                                      "path_with_ɄɳɨȻʘΔε_unicode",
 
  866                                      "path_with_🤔💩☢_emojis",
 
  867                                      "path_with_䭫顙_more_unicode" 
  870             auto nameMax = 
throwcall::badval(fpathconf(dirfd,_PC_NAME_MAX),-1,
"can't get max name length");
 
  871             auto ugly = std::to_string(nameMax);
 
  872             ugly.resize(nameMax,
'b');
 
  873             names.push_back(ugly);
 
  876         for (
const auto& ugly: names) {
 
  877             auto retval = mkdirat(dirfd,ugly.c_str(), 0777);
 
  878             if (retval == -1 && errno == EINVAL) {
 
  879                 std::cerr << 
"illegal dir name \" << ugly << \" tried \n";
 
  884             std::string file(ugly);
 
  886             auto fd = 
throwcall::badval(openat(dirfd, file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0744),
 
  897 int main(
int argc, 
const char *argv[]) {
 
  905         action.fAddToRange(test.first);
 
  907     auto remainingOptions = parser.
fParse(argc, argv);
 
  911         test->second->Execute(remainingOptions);
 
  913         std::cerr << 
"unknown action '" << action << 
"'\n";