Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C++] Memory Mapped Files, een interface

Pagina: 1
Acties:

  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
Beste Tweakers,

Ik ben bezig met een memory scanning tool in C++. Ik heb nu een werkend prototype dat vrij snel en accuraat werkt. Het enige nadeel is: Ik sla alle data op in een vector. Dat betekent dus, veel geheugengebruik. Ik heb gezocht naar een snelle oplossing, snel kwa performance dan :+, en kwam uit bij memory mapped files. Ik heb hier wat onderzoek naar gedaan, en het principe is me duidelijk. Echter krijg ik het niet voor elkaar om te bedenken hoe ik dit nu kan implementeren in mijn programma!

Wat ik eigenlijk graag zou willen is een interface die vanuit het bestaande stuk code bruikbaar is. Dan moet ik hieraan denken:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
void ClearResults();
void Add(MemoryBlockBase* block);
void SetResultType(MemoryScanValueType type);

// Deze methode zou ik ook kunnen vervangen door een functie die één element op een bepaalde index ophaalt, of een iterator.
const Vector<MemoryBlockBase*>& GetSearchResults() const;

const int GetResultCount() const;

const MemoryBlockBase* operator [] (const int x)
{
    return this->mFirstMillionResults[x];
};


Mijn vraag is eigenlijk als volgt. Hoe kan ik ervoor zorgen dat ik een onderliggende vector, array of ander soort lijst in een memory mapped file wordt opgeslagen? Of sla ik volledig de plank mis, en is er een veel gemakkelijkere oplossing? Ik weet dat ik in feite gewoon te maken heb met een stuk geheugen, en met memcpy de data gewoon raw kan opslaan.

p.s. Voor het geval dat iemand dit weet, ik gebruik de Win32 API functies voor de memory map, CreateFileMapping, MapViewOfFile en UnmapViewOfFile. Ik heb echter niet kunnen vinden hoe ik de grootte van de map verander. Is er toevallig iemand die dit weet?

Bij voorbaat dank!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

De pointer die je krijgt kun je casten naar eender wat. Wat je er daarna mee doet is jouw zaak, lijkt me?
Wat je code betreft, moet je't gewoon als een memory allocatie zien, die toevallig persistent gemaakt wordt door je OS.

Als er geen mogelijkheid is om met een API call de mapping + onderliggende file groter te maken, dan kun je eerst unmappen, file groter maken en opnieuw mappen.
Geen idee of Windows lazy allocation doet op die blokken, maar ik neem aan dat die operatie niet extreem duur is qua performantie (gegeven dat je dit niet bij elke 'add' operatie doet.

Ik vraag me echter af wat je denkt te bereiken. Je gaat de boel niet sneller maken door van snelle storage (memory) naar trage storage (disk) te gaan. Hoogstens gaat je OS via de page cache een soort overflow naar disk doen (als niet alles in RAM past) maar dat doet het OS ook voor je met de swap-file.

ASSUME makes an ASS out of U and ME


  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
Dankjewel voor je reactie. Ik heb nu een structuur die aardig werkt, althans, ik heb nog steeds een probleem. Ik heb 7 verschillende types die ik als templates doorgeef. deze types zijn: byte, short, int, int64, float, double en string. Allen van deze zijn primitieven, behalve de string. Hier heb ik dus het probleem dat ik de onderliggende buffer moet opslaan in plaats van de string class, die alleen een pointer naar de string heeft. Ik heb nu dit:

C++:
1
2
3
memcpy(&(this->basePtr[this->resultIndex]), &(pBlock->Address), sizeof(unsigned int));
memcpy((&this->basePtr[this->resultIndex++] + sizeof(unsigned int)), pBlock->Value.c_str()
    , pBlock->Value.length());


Waar Value == std::string en address == unsigned int (4 bytes). Dit werkt alleen niet goed. Ik krijg verkeerde data terug. De resultIndex is de index van het array op dit moment, niet de positie van de pointer per byte.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:23

.oisyn

Moderator Devschuur®

Demotivational Speaker

evolution536 schreef op zondag 05 mei 2013 @ 21:27:
p.s. Voor het geval dat iemand dit weet, ik gebruik de Win32 API functies voor de memory map, CreateFileMapping, MapViewOfFile en UnmapViewOfFile. Ik heb echter niet kunnen vinden hoe ik de grootte van de map verander. Is er toevallig iemand die dit weet?
Kan niet. Overigens moet ik zeggen dat ik ook totaal niet snap waarom het een oplossing is voor je probleem. Memory mapped files gebruik je voor persistente storage (of in het geval van Windows ook voor cross process communication). Misschien wil je dat wel, maar dan zul je nog altijd zelf de moeite moeten doen om slechts een deel actief in het geheugen te houden. Je app gaat niet plots minder geheugen gebruiken alleen maar omdat je alles in een MMF opslaat.

[ Voor 6% gewijzigd door .oisyn op 06-05-2013 11:29 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
mmap voor IPC is ook op Linux niet ongebruikelijk hoor. Maar inderdaad, het lost geen enkel probleem op.

Wat je in dit geval nodig hebt (geheugengebruik >> RAM) is cache-aware algoritmes. En databases hebben meestal een fatsoenlijke implementatie daarvan.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

De grootte van een gemapped blok kan je niet veranderen achteraf.

Er zijn wel andere mogelijkheden:
1) Je blokken indirect aan elkaar hangen. Je bouwt dan een datastructuur die de blokken beheerd en adressen (offsets) kan omzetten naar een adres/offset in een blok.
2) Je kan met VirtualAlloc een heel groot blok reserveren en dan naar mate je meer nodig hebt kan je stukken committen (en stukken die je niet meer nodig hebt vrijgeven). Omdat je eerst reserveert, kan je garanderen dat je altijd blokken in het virtueel geheugen achter elkaar hebt staan. Vooral bruikbaar in 64-bit mode wegens de grote VM adres-ruimte
3) Je kan met VirtualAlloc en de physical memory opties zelf de virtueel geheugen table van je proces bewerken. Je kan dan blokken RAM committen en door de CPU "gratis" laten unmappen uit virtueel geheugen (sidenote: dit is kinda undocumented, en je user account moet een speciale permission hebben)

Hoe dan ook, je hebt maar X geheugen op je PC, en een groot stuk gebruiken gaat er altijd voor zorgen dat Windows het naar de pagefile gaat verschuiven (die is enorm traag vergeleken met RAM). Memory mapped files zijn ook een soort pagefile wat dat betreft, je hebt een HD als backing store voor je geheugen.

Ik zou eerst eens goed kijken of je je algoritme niet kan veranderen zodat je minder (stukken) van je data tegelijk nodig hebt, dan kan je een stuk minder geheugen in gebruik hebben, en dat kan ook tijdswinst opleveren.

-niks-


  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
Dus als ik het goed begrijp zou ik geen MMF nodig hebben. Ik zou net zo goed af kunnen met een algoritme dat op de juiste manier mijn vector van zoekresultaten wegschrijft naar een file om het geheugengebruik te reduceren?

In wat voor richting moet ik hier denken? Het doel is namelijk dat ik een tool schrijf die ook snel en stabiel draait op oudere machines. Ik heb toevallig een machine met 16 GB werkgeheugen, maar ik vind dat een memory scanning tool niet af kan met 1.5 GB geheugengebruik. Daarnaast is het ook nog langzaam om 30 miljoen resultaten te deleten uit het geheugen. Het deleten van ~1 miljoen en vervolgens de rest verwijderen door simpelweg de cache file op de HD te verwijderen zou stukken sneller gaan!

  • Laurens-R
  • Registratie: December 2002
  • Laatst online: 29-12-2024
Komt die 1.5GB geheugengebruik ook niet door het feit dat jij 16 GB hebt (aangezien je aangeeft dat het een memory scan tool is)? M.a.w. als er minder geheugen in de machine aanwezig is; resulteert dat dan ook niet in een kleinere dataset? Hoewel ik het alsnog een behoorlijk slok aan data vind.

Verder kan je nadenken over hoe je je informatie op slaat in het geheugen; kies de juiste datatypes voor de juiste informatie. Als je bijvoorbeeld een aantal bool values hebt kan je deze beter bit shiften in bijvoorbeeld een char, omdat een bool minimaal 8 bits alloceert. (icm een x aantal GBs aan geheugen wat je afscanned kan dat al hard gaan).

En zo kan ik nog wel even doorgaan; hoewel dit lastig is in te schatten als ik niet precies weet wat je precies wilt opslaan en waar je precies naar op zoek bent in die dataset. Bij elk scenario is er bijvoorbeeld ook een x aantal data structures die daarvoor effectief zijn.

Ik weet trouwens ook niet wat deze geheugen scan inhoud? Je kan niet buiten de boundaries kijken van het gealloceerde geheugen van app in kwestie.

[ Voor 71% gewijzigd door Laurens-R op 07-05-2013 09:16 ]


  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
Laurens-R schreef op dinsdag 07 mei 2013 @ 09:02:
Komt die 1.5GB geheugengebruik ook niet door het feit dat jij 16 GB hebt (aangezien je aangeeft dat het een memory scan tool is)? M.a.w. als er minder geheugen in de machine aanwezig is; resulteert dat dan ook niet in een kleinere dataset? Hoewel ik het alsnog een behoorlijk slok aan data vind.

Verder kan je nadenken over hoe je je informatie op slaat in het geheugen; kies de juiste datatypes voor de juiste informatie. Als je bijvoorbeeld een aantal bool values hebt kan je deze beter bit shiften in bijvoorbeeld een char, omdat een bool minimaal 8 bits alloceert. (icm een x aantal GBs aan geheugen wat je afscanned kan dat al hard gaan).

En zo kan ik nog wel even doorgaan; hoewel dit lastig is in te schatten als ik niet precies weet wat je precies wilt opslaan en waar je precies naar op zoek bent in die dataset. Bij elk scenario is er bijvoorbeeld ook een x aantal data structures die daarvoor effectief zijn.

Ik weet trouwens ook niet wat deze geheugen scan inhoud? Je kan niet buiten de boundaries kijken van het gealloceerde geheugen van app in kwestie.
Goed punt, klinkt me ook niet onlogisch. ik zal is onderzoeken of het feit dat ik zo veel memory heb inderdaad leid tot een grotere hoeveelheid data als resultaten. Ik heb het niet mogelijk gemaakt te scannen naar bool waarden, alleen byte, short, int, int64, float, double en string, waar string de String class uit het U++ framework, ongeveer, zoals std::string. Mijn memoryblock ziet er zo uit.

C++:
1
2
3
4
5
6
7
8
9
10
struct MemoryBlockBase : Moveable<MemoryBlockBase>
{
     unsigned int Address;
};

template <class T>
struct MemoryBlock : public MemoryBlockBase
{
     T Value;
};


Hier zit naar mijn vermoeden ook een zekere overhead in, aangezien ik de resultaten opsla als: MemoryBlockBase* ter generalisatie. Dat betekent dat ik dus ook iedere keer een new en delete call heb, terwijl ik niet eens een constructor nodig heb! Ik sla bijvoorbeeld alleen een unsigned int en een float achter elkaar in het memory op. De Moveable template is een lege class, sizeof == 0. Deze is alleen nodig voor structs om in een Vector (U++ vector) te worden geplaatst. Hier kan ik eventueel om heen als ik een linked list gebruik, die in de meeste gevallen minder snel is.

Het probleem van het opslaan van deze 'T' in een file wordt bij het opslaan van een string het feit dat de onderliggende buffer moet worden opgeslagen i.p.v. de class inclusief pointer. ;) Zou het ook nog kunnen zijn dat ik de resultaten opsla als: Vector<MemoryBlockBase*> en voor ieder resultaat de constructor aanroep met new, door fragmentatie het geheugengebruik oploopt?

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Fragmentatie kan je voorkomen door een custom allocator te gebruiken in je container (de STL containers hebben een template parameter die je kan gebruiken), of je kan de global operator new overriden, ervanuitgaande dat je kennis hebt van je allocatie-patroon.

Ik weet niet in hoeverre jouw geheugen gebruik exact "dynamisch" is, maar als je slechts new't en daarna alleen aan het eind hoeft op te ruimen, dan je met een heel simpele custom alloctor uit de voeten (en gewoon free een no-op maken).

Maar als je scant naar iets, kan je dan niet veel beter een geindexeerde structuur opbouwen ofzo?
Het is nogal afhankelijk van wat je zoekt, waar je zoekt, en in welke volgorde je zoekt.

Gegeven dat je 7 types hebt, kan je dan wellicht niet eerst alles van type A laden, dan alles van type A zoeken, en dan alles (behalve je resultaten) weggooien, en verder gaat met B enz? Dan reduceer je je geheugen gebruik enorm.
En als je exacte string matching doet, kan je misschien beter een hash-map bouwen ofzo.

Het feit dat jij het een memory scanner noemt is leuk en aardig, maar je laad alles zelf in, dus je kan net zo goed op een andere wijze scannen.

Er zijn ook andere tools die wellicht beter zijn (searching is niet echt een niet-onderzocht gebied). Als je data gestructureerd en statisch is, heb je al geprobeerd om het in MSSQL te pleuren en een paar indices aan te leggen?

Niet altijd is zelf in C++ coden de snelste oplossing :)

-niks-

Pagina: 1