Problem mit ReadFile()
-
Ja, das habe ich zumindest beim Lesen auch festgestellt. Beim Schreiben kommen so Werte um 120 MB/s raus, die auch tatsächliche Benchmarks anzeigen.
Und ich hatte halt gehofft, mit CreateFile und ReadFile könnte ich das umgehen.
-
SeppJ schrieb:
Kurz gesagt: Du versuchst da gerade unfreiwillig, einen Benchmark für den Arbeitsspeicher zu schreiben.
Ich hab mich auch mal dran versucht... Meiner Meinung nach sollte das ja der richtige Weg sein:
/*timer.hpp*/ #include "windows.h" #include <cassert> #include <stdexcept> struct large_integer_t { typedef __int64 integral_type; operator float() const { return static_cast<float>( static_cast<integral_type>(*this) ); } operator integral_type() const { return data.QuadPart; } operator integral_type() { return data.QuadPart; } large_integer_t() : data(LARGE_INTEGER()) {} large_integer_t(const LARGE_INTEGER& data) : data(data) {} large_integer_t& operator-= (const large_integer_t& other) { data.QuadPart -= other.data.QuadPart; return *this; } private: LARGE_INTEGER data; }; large_integer_t operator- (const large_integer_t& lhs, const large_integer_t& rhs) { large_integer_t tmp(lhs); tmp -= rhs; return tmp; } class timer_t { public: typedef float second_t; timer_t() : begin(get_timestamp()) #if !defined (NDEBUG) , stopped(false) #endif //#if !defined (_NDEBUG) { end = begin; } void stop() { #if !defined (NDEBUG) stopped = true; #endif //#if !defined (_NDEBUG) end = get_timestamp(); } second_t get_seconds() const { assert(stopped); return (end-begin)/static_cast<second_t>(get_frequency()); } private: #if !defined (NDEBUG) bool stopped; #endif //#if !defined (_NDEBUG) static large_integer_t get_frequency() { LARGE_INTEGER ret_val; BOOL succeed = QueryPerformanceFrequency(&ret_val); if(!succeed) throw std::runtime_error("calling QueryPerformanceFrequency failed"); return ret_val; } static large_integer_t get_timestamp() { LARGE_INTEGER ret_val; BOOL succeed = QueryPerformanceCounter(&ret_val); if(!succeed) throw std::runtime_error("calling QueryPerformanceCounter failed"); return ret_val; } large_integer_t begin; large_integer_t end; };/*file_op.hpp*/ #include "windows.h" #include <stdexcept> class file_t { public: bool is_open() const { return fd != INVALID_HANDLE_VALUE; } bool bad() const { return !is_open() || op_failed; } bool good() const { return !bad(); } void write(char* const first, std::size_t length) { if(bad()) return; DWORD length_wrote; BOOL succeeds = WriteFile(fd, first, static_cast<DWORD>(length), &length_wrote, NULL); op_failed = !succeeds || (static_cast<std::size_t>(length_wrote) != length); } void read(char* first, std::size_t length) { if(bad()) return; DWORD length_read; BOOL succeeds = ReadFile(fd, first, static_cast<DWORD>(length), &length_read, NULL); op_failed = !succeeds || (static_cast<std::size_t>(length_read) != length); } static file_t create(const char* filename) { HANDLE hwnd = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); return file_t(hwnd); } static file_t open(const char* filename) { HANDLE hwnd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); return file_t(hwnd); } static void close(file_t& to_close) { if( !to_close.is_open() ) return; CloseHandle(to_close.fd); to_close.fd = INVALID_HANDLE_VALUE; } private: explicit file_t(HANDLE fd) : fd(fd), op_failed(false) {} HANDLE fd; bool op_failed; }; void delete_file(const char* filename) { BOOL succeed = DeleteFile(filename); if(!succeed) throw std::runtime_error("cannot delete file"); }/*main.cpp*/ #include "timer.hpp" #include "file_op.hpp" template <class T, std::size_t n> std::size_t size_of(const T(&)[n]) { return n; } void do_and_print(const char* filename, std::size_t size_in_mb); #include <iostream> int main() { const char* filenames[] = { "C:/tmp.txt", "E:/tmp.txt", "L:/tmp.txt", "H:/tmp.txt" }; std::size_t megabyte_count; std::cout << "wie viele MB sollen jeweils gelesen/geschrieben werden?" << std::endl; std::cin >> megabyte_count; for(std::size_t i = 0; i != size_of(filenames); ++i) { std::cout << filenames[i] << std::endl; do_and_print(filenames[i], megabyte_count); } #if 0 std::cout << "Taste..." << std::endl; std::cin.ignore(); std::cin.get(); #endif } #include <algorithm> #include <iomanip> #include <vector> void do_and_print(const char* filename, std::size_t size_in_mb) { if(size_in_mb == 0) return; std::ios_base::fmtflags flag_backup = std::cout.flags(); std::cout << std::setprecision(3) << std::fixed; const std::size_t MB = 1024 * 1024; const std::size_t buffer = size_in_mb * MB; bool created_file = false; std::vector<char> to_write(buffer, '1'); { file_t file = file_t::create(filename); created_file = file.is_open(); timer_t time; file.write(&to_write[0], to_write.size()); time.stop(); if(file.bad()) std::cout << "schreiben fehlgeschlagen" << std::endl; else std::cout << "schreiben (" << size_in_mb << " MB): " << time.get_seconds() << "-> " << size_in_mb/time.get_seconds() << " MBps" << std::endl; file_t::close(file); } std::vector<char> to_read(buffer, '0'); if(created_file) { file_t file = file_t::open(filename); timer_t time; file.read(&to_read[0], to_read.size()); time.stop(); if(file.bad()) std::cout << "lesen fehlgeschlagen" << std::endl; else std::cout << " lesen (" << size_in_mb << " MB): " << time.get_seconds() << "-> " << size_in_mb/time.get_seconds() << " MBps" << std::endl; file_t::close(file); } if(to_write != to_read) std::cout << "kaputt ;)" << std::endl; if(created_file) delete_file(filename); std::cout.flags(flag_backup); }wie viele MB sollen jeweils gelesen/geschrieben werden? C:/tmp.txt schreiben (5 MB): 0.162-> 30.818 MBps lesen (5 MB): 0.228-> 21.895 MBps E:/tmp.txt schreiben (5 MB): 0.180-> 27.835 MBps lesen (5 MB): 0.003-> 1495.359 MBps L:/tmp.txt schreiben (5 MB): 0.149-> 33.455 MBps lesen (5 MB): 0.054-> 92.113 MBps H:/tmp.txt schreiben (5 MB): 1.983-> 2.521 MBps lesen (5 MB): 0.253-> 19.797 MBpswie viele MB sollen jeweils gelesen/geschrieben werden? C:/tmp.txt schreiben (50 MB): 1.621-> 30.850 MBps lesen (50 MB): 1.769-> 28.257 MBps E:/tmp.txt schreiben (50 MB): 1.397-> 35.779 MBps lesen (50 MB): 0.035-> 1416.357 MBps L:/tmp.txt schreiben (50 MB): 1.222-> 40.904 MBps lesen (50 MB): 0.383-> 130.452 MBps H:/tmp.txt schreiben (50 MB): 5.537-> 9.030 MBps lesen (50 MB): 2.360-> 21.189 MBpswie viele MB sollen jeweils gelesen/geschrieben werden? C:/tmp.txt schreiben (200 MB): 6.472-> 30.902 MBps lesen (200 MB): 6.657-> 30.043 MBps E:/tmp.txt schreiben (200 MB): 6.053-> 33.041 MBps lesen (200 MB): 0.211-> 949.562 MBps L:/tmp.txt schreiben (200 MB): 4.585-> 43.617 MBps lesen (200 MB): 1.978-> 101.106 MBps H:/tmp.txt schreiben (200 MB): 26.159-> 7.645 MBps lesen (200 MB): 9.288-> 21.534 MBpsC+E sind Partitionen auf ner uralten IDE Platte. Bei E ist die Komprimierung aktiviert, deshalb die utopischen Lese-Werte^^
L ist nen RAID5 über 5 SATA Platten, da sollte aber einiges an Geschwindigkeit durch die Verschlüsselung verloren gehen. Und natürlich auch schon durch den Controller - aber der auf dem Board muss reichen, bis ich mal im Lotto gewonnen habe

H ist nen USB-Stick
Scheint doch gar nicht mal so unrealistisch zu sein.
bb
so, das war jetzt das letzte edit - die einzige (für mich) offensichtliche schwäche liegt an der mangelnden fehlerbehandlung und dem fehlenden RAII für file - aber ich wollts auch nich total übertreiben^^
-
Also der Code hat mich schon beeindruckt
Leider ist er in meinen Augen so komplex, das ich ihn, oder Teile davon, nicht übernehmen kann. Ich habe nicht nur mit der WinAPI Schwierigkeiten, sondern schon mit der OOP 
-
den timer musst du nicht verstehen, der rest sollte aber auch für einen anfänger relativ gut zu verstehen sein?!
wo liegt denn dein problem genau? oder beser: wo bist du denn in deinem buch und welches liest du denn?
-
Ich habe den 'Der C++ Programmierer' von Ulrich Breymann und bin im letzten Kapitel, bevor die OOP angeschnitten wird, genauer bei Programmstrukturierung.
Und falls Du die timer.hpp meinst, da erkenne ich nur durch die cout-Ausgaben, das sie wohl mit der Zeitmessung zusammen hängt und just die funktioniert bei mir ja einwandfrei.
-
na gut, dann lies ma noch paar kapitel, dann wirst dus auch versthen

-
Ich habe mal Dein Code bei mir kompilieren lassen und (ohne einen Zweifel gehabt zu haben ;)) die Werte waren auch bei mir realistisch.
Gibt es einen Grund, warum Du Deine Headerfiles .hpp genannt hast? Die werden doch sonst immer nur .h genannt?
-
lemon03 schrieb:
Ich habe mal Dein Code bei mir kompilieren lassen und (ohne einen Zweifel gehabt zu haben ;)) die Werte waren auch bei mir realistisch.
Gibt es einen Grund, warum Du Deine Headerfiles .hpp genannt hast? Die werden doch sonst immer nur .h genannt?
.hpp ist eine nette Abgrenzung zu C-Headern, wird fast öfters verwendet als .h
-
Wie macht man das denn in einer IDE? CodeBlocks zB bietet scheinbar nur h.files, cpp.files und leere Files an.
Ich kann mir kaum vorstellen, das man die dann händisch umbenennt?
-
Ahja, inzwischen ist es mir eingefallen. Einfach bei leeres File *.hpp eingeben.