Jump to content

C Windows - Is heap/stack pointeris? [bija: nevar ielādēt rindu no resursa]


Baigais Janka
 Share

Recommended Posts

Jaunais "Is heap/stack pointeris" - no posta #11

 

======================

 

Nu, galīgs svieksts... Vai nu kvalifikācija zudusi, vai kas (sen nebiju windows jomā programmējies), bet nu murgs... Tātad - ir DLL-is, DLL-a resursos ir stringi. Izsauc funkciju arī DLL-a ietvaros. Tad nu lūk

TCHAR sz[1024];
HRSRC hRes;
DWORD dw;
 
SetLastError(0);
hRes = FindResource(hInst, MAKEINTRESOURCE(uID), RT_STRING);
dw = GetLastError(); // 1814: "The specified resource name cannot be found in the image file."
 
SetLastError(0);
hRes = FindResource(GetModuleHandle(_T("name.dll")), MAKEINTRESOURCE(uID), RT_STRING);
dw = GetLastError(); // 1814: "The specified resource name cannot be found in the image file."
 
SetLastError(0);
LoadString(hInst, uID, sz, elemof(sz));
dw = GetLastError(); // 0

LoadString nostrādā bez problēmām, viss ielādējas, a FindResource atgriež NULL un erroru. Kādi zemūdens akmeņi tur var būt, lai šitāda šaize notiktos? Vajag tieši FindResource, jo būs daudzvalodu mašinērija, ta FindResourceEx tiks lietots nākotnē. Ideju nav - kur vispār rakt sākt... hInst iraid korekta hinstnce - tiek savākta sākumā pie DLL_PROCESS_ATTACH.

Labots - Baigais Janka
Link to comment
Share on other sites

Njā, sen nekas tāds nav darīts…

 

Mani drusku mulsina trešā argumenta docs:

 


lpType [in]

Type: LPCTSTR

The resource type. Alternately, rather than a pointer, this parameter can be MAKEINTRESOURCE(ID), where ID is the integer identifier of the given resource type. For standard resource types, see Resource Types. For more information, see the Remarks section below.

Kas notiek, ja izmanto to MAKEINTRESOURCE(ID) arī trešajam argumentam?



Nē, nekas nenotiks ar to 3. argumenta nomaiņu.

 

 

FindResource w/ RT_STRING is not as simple as that as they are stored in blocks

via stackoverflow (1), stackoverflow (2)

Link to comment
Share on other sites

Baigais Janka
(labots)

Jap, ar jau atradu :)

Nu ja, viss smuki strādā, bet nu SDK dokumentācijā ne vārda par šito joku :(

Labots - Baigais Janka
Link to comment
Share on other sites

Inspektors Caps

Interesanti... Pašam līdz šim nav bijusi vajadzība dažādām valodām, bet netālā nākotnē iespējams būs.

 

Kādu tad uztaisīji gala variantu? Ar to "#" simbolu vai kaut kā ar LoadResource?

Link to comment
Share on other sites

Baigais Janka
(labots)

Atgriež pointeri un garumu, mani tas apmierina, "\0" beigās nebij obligāta :). Unlock un Free iraid "pustiškas", bet nu solīdumam atstāju.

LPWSTR ResGetStringPtrLen(HINSTANCE hInst, UINT uID, WORD wLangID, LPUINT lpLenCch)
{
 UINT u;
 HRSRC hRes;
 HGLOBAL hGlobal;
 LPTSTR szRes, szStrPtr;
 szStrPtr = NULL;
 *lpLenCch = 0;
 if ((hRes = FindResourceEx(hInst, RT_STRING, MAKEINTRESOURCE((uID >> 4) + 1), wLangID))) {
  if ((hGlobal = LoadResource(hInst, hRes))) {
   if ((szRes = (LPTSTR) LockResource(hGlobal))) {
    szStrPtr = szRes;
    for (u = 0; u < (uID & 15); u++) {
     szStrPtr += (1 + (UINT)*szStrPtr);
    }
    UnlockResource(szRes);
   }
   FreeResource(hGlobal);
  }
 }
 if (szStrPtr) {
  *lpLenCch = *((LPUINT)szStrPtr);
  szStrPtr++;
 }
 return szStrPtr;
}
Labots - Baigais Janka
Link to comment
Share on other sites

Baigais Janka

Nu, prakstiski tas pats jau ir, ko esu sadzejojis :)

Nu, viss šancē OK, es tik gānos, ka dokumentācijā bij varējuši pateikt, ka stringi tā viltīgi pakās allocējas, a to - uz ikonām un bildēm viss šancē, uztaisi tāpatās stringu - čušs.

Link to comment
Share on other sites

 

 

Nu, viss šancē OK, es tik gānos, ka dokumentācijā bij varējuši pateikt, ka stringi tā viltīgi pakās allocējas, (..)

Iz FindResource() docs:

 

 

String resources are stored in sections of up to 16 strings per section. The strings in each section are stored as a sequence of counted (not necessarily null-terminated) Unicode strings. The LoadString function will extract the string resource from its corresponding section.
Link to comment
Share on other sites

Baigais Janka

No šitā teksta vien to matemātiku neizvilksi... Nē nu, loģiski, ka es pat šito biju palaidis garām, galu galā - vai pēdīgās rindas :)

Link to comment
Share on other sites

Matemātiku varbūt arī neizvilksi, bet hints, ka jādomā ko grudrāku, gan tur skaidri uzrakstīts.

Link to comment
Share on other sites

Baigais Janka

Netaisīšu jaunu pavedienu, iejautāšos šepat - kāds būtu viegls & elegants veids nodetektēt, vai atmiņas pointeris pieder stekam, vai hīpam? Iekš tā paša Windows & API. Vai der arī - iraid iekš steka, vai hvz kur :) HeapValidate() gan atgriež pareizu vērtību, bet ir nervozs debugēšanas laikā - met visādus papildus dialogus laižot caur studiju (ok, var jau būt ar pragmā var atslēgt), bet galvenais - iraid laika ziņā rijīga fuinkcija, kas vairāk derīga debugiem. Jālieto modulī, kurš kakraz ieviests, lai štelli paātrinātu. Nu, prakstiski teju vai der uz aci piemešana - ja pointeris lielāks par SP, tātad ir steks :) Bet nu mest kauču kādu inline assm nešķiet labākā ideja, varbūt iraid API funkcija?

Link to comment
Share on other sites

Nez, nav dzirdēts. IMHO tā nav īpaši tipiska vajadzība. Kam Tev tā? Tiešām tas ir labākais algoritms?

 

Rekur ir veids, kā dabūt threada steka sākumu/beigas, taču tas izmanto nedokumentētas funkcijas, tāpēc ar to uzmanīgi.

 

Vēl var izmantot GetThreadContext(), lai dabūtu esp, un tad otra puse ir tikai noskaidrot steka izmēru, kas pēc defaulta ir 1MB, taču to var norādīt kompilators .EXE headerī citādāku, vai arī pa tiešo CreateThread(), tāpēc pilnībā uz to labāk nepaļauties, ja vien visi interesējošie threadi nav Tevis paša pārziņā.

 

Vispēdīgi, ir arī GetCurrentThreadStackLimits() funkcija, kas ir vistuvāk tam, kas Tevi interesē, taču tā, diemžēl, ir pieejama tikai sākot ar Windows 8. :(

Labots - Vilx-
Link to comment
Share on other sites

Baigais Janka

Njā, nekas sevišķi labs nava... Nē nu, protams, algoritmu jau var izmainīt...

Pamatideja ir tāda: ir "typedef struct" obžekti - un varu es viņus definēt kā lokālos mainīgos - uz aci piemetot, ka lietojot zināms bufera izmērs netiks pārsniegts, vai arī uztaisīt ar malloc-u, ja bufera izmērs paredzams liels. Pirmais variants fiksais, otrs, protams, būs lēnāks. Mašinērija tāda, ka ja nu tomēr vēlāk lietojot bufera izmērs tiks pārsniegts, viņš reallocēsies - kur tu liksies, bet tas ir "unlikely"). Tad struktūras laiž sistēmā iekšā, un tā nu viņas tur klejo. Pirmkārt, inicializācija - te būtu jāzin, kas par zvēru - vai allocēt atmiņu buferim vai lietot vietējo. Otrkārt - jebkurā mirklī var uztaisīt free - tad arī, ja steks, tad tik iestellē, ka brīvs un visi mainīgie invalīdi, ja malloc-s - tad reāli atbrīvo (pa sistēmu klejo pointeris uz pointeri, pirmajā gadījumā struktūras adrese paliks, kā ir, otrajā gadījumā - atbrīvojot iestellē NULL).

Protams, var jau uztaisīt, ka pie malloc ieliek kauču kādu savu identifikātoru struktūrā, lokālajam - savu. Bet tā izdalīšana - stekā vai lokāli - visu laiku mainās. Ta nu lai izbēgtu no liekas iespējamas regresijas, piemēram, iepriekš steks, tagad malloc, a inicializācija paliek, kā stekam :) Tāpēc bija doma, ka taisi viņu, kā gribi, maini kauču 100x dienā - viņš tiek atpazīts un pareizas darbības veiktas.

Link to comment
Share on other sites

Īsti neiebraucu. Kāpēc neizmantot mallocu (vai tā ekvivalentu) no sākuma līdz beigām? Lēni? Rezervē uzreiz 1MB vietas pēc defaulta un dali tik no tās bez turpmākiem malloca izsaukumiem. Tas pats vien kas steks tas sanāk. To vienu ekstra malloc darba sākumā nejutīsi. Uztaisi baru ar funkcijām, kas šīs operācijas ļauj izdarīt 1 rindiņā, un dzīvo laimīgs! Un kods arī pēc tam būs vieglāk saprotams citiem, bez tās ezotēriskās pointera atrašanās vietas detektēšanas.

 

Upd: Pie tam, īsti neuztvēru, kā Tu gatavojies "izdalīt vietu stekā"? Stekā (bez kaut kādas ķīmijas) atmiņu var dabūt tikai vienā veidā - lokāli mainīgie (nu, vai arī funkciju parametri, kas tas pats basically arī ir). Ja tās struktūras, kā saprotu, nāk un iet, tad... negribi parādīt kauču konceptuālu pseidokodu, kā Tu to plāno realizēt? :blink:

Labots - Vilx-
Link to comment
Share on other sites

Baigais Janka

Lokāli - tas ir vienkārši lokāli :) Izmantotas tiek no tās funkcijas, kur izdalītas, un "uz leju". Tur nekādas ķīmijas nav. Vienkārši vienā brīdī viņas var atbrīvot, bet klejojot tālāk un arī dziļāk, viņas var tikt pieprasītas izmantošanai no jauna.

Par to "izdalīt uzreizi", nu tiek tāda bloku alokācija man še izmantota - tipa, pašu atmiņas managements, kad sīkām struktūrām tiek izdalīti lieli bloki. Ja aptrūkstās struktūrām vietas, izdala jaunu bloku (glabā, kā listu), ja sistēmai - tad atbrīvo kādu brīvo bloku. Bet tas i kerneļa līmenī, un nav iekš windows, un pārnest to man slinkums :) Šitas variants ar steka ponteri man kauču kā pirmajā brīdī vienkāršāks likās. Laikam kerneļa izstrādē pēdējā laikā par daudz iegrimis esmu, ar windows maz darīšanas :)

Link to comment
Share on other sites

Jūzermodē parasti uzsvars ir uz lasāmāku kodu nevis uz efektīvāku kodu, jo koda parasti ir ar kārtu līdz divām vairāk nekā kerneļmodē, un tam pāri iet developeri baros. :)

 

IMHO tā "izdalīšana uzreizi" nemaz tik liels čakars nav, un beigu beigās būs arī vienkāršāk. :)

Link to comment
Share on other sites

Inspektors Caps

Interesanti būtu uzzināt kas ar to atmiņu tāds šausmīgs tiek darīts, ka heap atmiņa ir lēnāka par stack.

 

Un, ja ir savs atmiņas managements, tad jau tur ne HeapAlloc jāņem, bet VirtualAlloc, kas stāv tam apakšā.

Link to comment
Share on other sites

Baigais Janka

Nu, heap atmiņa vienmēr būs lēnāka par steku, jo steks jau ir tikai pointera pabīdīšana. VirtualAlloc īsti neder, jo kods tāds ne īsti windowsisks, varbūt pamatmašiņā, kurai programēju, kauču ko izmantošu no idejām, ko tagad te rakstu. Vienkārši sakārojās atkal ko uz Windows paprogramēt. A pamatmašiņā - tur i viss no svara, pāris ļimonu lietotāju dzenā tādus datu apjomus, ka ir vairāk kā būtiski, vai atmiņa stekā, vai no malloka, un ja vēl tam, nedo dies, vēl "spaiņi" beigušies :)

Link to comment
Share on other sites

Sorry par jautājumu, bet vai Tu gadījumā nenodarbojies ar premature optimizations? Varbūt jābeidz rakstīt C un jāpievēršas optimizēta ASM koda rakstīšanai? Jo tas C kods jau tāpat rezultātā sakompilēsies/saoptimizēsies pavisam negaidītā veidā…

  • Patīk 1
Link to comment
Share on other sites

Inspektors Caps

 

 

Nu, heap atmiņa vienmēr būs lēnāka par steku, jo steks jau ir tikai pointera pabīdīšana.

Nu un kāda tad ir heap? Vai tad steks tāpat nav virtuālajā atmiņā? Un virtuālajai atmiņai CPU tak iekš MMU hardwariski pārtulko adreses. Vēl šodien viss tāpat reāli notiek kešatmiņā un RAM latency vairs nespēlē dižu lomu.

 

Tas viss ir reāli testēts vai tikai tāds pieņēmums? Man liekas, ka tur ir jābūt īpaši kretīniskam intensīvam read/write pa dažādām adresēm tajā lielajā masīvā, lai rastos kāda atšķirība performancē, ja tāda vispār būs.

Link to comment
Share on other sites

Baigais Janka

Viss ir testēts un pārtestēts līdz vemšanai, un par performanci - te par procenta daļām cīņa notiekās. Tieši tāpēc arī tiek lietota bloku alokācija, praktiski tas, par ko Vilx- ieteicās - nevis ņem objektam malloc/free, bet vienreiz pagrābj kārtīgu kluci n-objektiem, ar konkrēto izmēru, kura iekšienē tad arī pseidorezervē un atbrīvo atmiņu. Ir tam visam fiziski nomērama jēga. Steks ne visur der gan - kādi 4k tik tam atvēlēti (par kerneli runāju), bet šajā konkrētajā gabaliņā, ko rakstu, tas lomu nespēlē.

Link to comment
Share on other sites

Inspektors Caps

Interesanti, interesanti... Tā ziņkārei - a CPU ir kāds? Nekur jau nav teikts... Varbūt Tu mums te vispār par ARM7 runā. :D

Link to comment
Share on other sites

Cilvēku, saproti, uztrauc tas, ka malloc() izsaukums ir ilgāks nekā lokālā mainīgā izveidošana. :)

 

Mans viedoklis - viss atkarīgs no tā, cik daudz šādus buferīšus vajag sekundē izveidot (vai tā vispār ir performance-kritiska vieta?). Ja relatīvi nedaudz (pārdesmit?), tad malloc() performance būs vairāk nekā apmierinoša, un nav jēgas iespringt.

 

Ja vajag daudz daudz daudz (simitiem tūkstošu?), tad jātaisa savs allokators, kurš ņems no speciāla bufera. Vēl var padomāt par datu struktūru un algoritmu pielāgošanu CPU kešam. Būvējot uz visādām jocīgām ierīcēm ar embedded procesoriem to diezi vajag (tādiem vispār ir kešatmiņa?)

 

Viss ir testēts un pārtestēts līdz vemšanai, un par performanci - te par procenta daļām cīņa notiekās.

Kāda jēga no tādas optimizācijas, kas knapas procenta daļas uzlabo? :blink:
Link to comment
Share on other sites

Baigais Janka

Redz, pie milzu datu apjomiem, arī procenta daļas ir pamanāmas. Tā, uz aci piemetot, ar vienu tādu kārbu gandrīz vai Latvijai būtu gana, lai nodrošinātu mobīlo izeju internetā, nezi, vai pāris miljoni vienlaicīgi te ir iezvanījušies. Nu, OK, divas kastes var uzlikt :)

Jebkurā gadījumā, es ceru, ka nedaudz saprotu, ko daru :) Tāpēc cenšos uzdot jautājumu formā "kā konkrēto lietu izdarīt", nevis "a varbūt to var arī savādāk izdarīt", jap, var jau būt, ka var, bet es to kodu rakstu, un man pa viņu arī ķeskāties turpmāk, tad, kā nu māku, tā maunu, ja kādam kas var nepatikt - ta tas i darba devējs :) Un kodu revjūvē bars revjūveru, tāpēc vēl visas štelles tiek n-tās reizes apdomātas un pārdomātas. Un, loģiski, bieži arī atmestas atpakaļ pārstrādāšanai:)

Link to comment
Share on other sites

Mani vēl drusku izbrīnīja šī frāze:

 

 

Tāpēc bija doma, ka taisi viņu, kā gribi, maini kauču 100x dienā - viņš tiek atpazīts un pareizas darbības veiktas.

Precīzāk - "kauču 100x dienā"… Frāze tāda, it kā konkrētajiem dzelžiem reallocēt atmiņu 1x 15 minūtēs sanāktu baisi dārgi… Bet nu labi, ko gan es zinu… Ja jau cilvēks saka, ka jācīnās par procenta daļām, tad gan jau algoritmi ir jau nooptimizēti līdz pēdējam :crazy:

Link to comment
Share on other sites

Baigais Janka

binary, 100x dienā bija domātas izmaiņas kodā :) Lai minimizētu regresijas, jo par tām dod kārtīgi pa asti.

Link to comment
Share on other sites

Nezinu, ko Tu ar "100x dienā" biji *domājis*, bet *uzrakstīji* nevis par izmaiņām kodā, bet par to, ka vienus un tos pašus datus gribi bīdīt starp steku un heapu, atkarībā no datu izmēra konkrētajā brīdī.

 

 

 

Redz, pie milzu datu apjomiem, arī procenta daļas ir pamanāmas.

Ir tāda tupa spēlīte, "Mortal Coil" (da nu daudz tādu). Faktiski "mīkla", kuras risināšanai jāuzraksta softu, jo cilvēcīgā veidā tālāk par 10.-20. leveli tikt nereāli, a tur kopā virs 1k leveļu. Kaut kādā brīdī softam jau vajag nedēļu, lai atrisinātu leveli (tas pie kāda 50. leveļa varētu būt) - nu tad sēdi un domā, ko darīt. Var optimizēt darbu ar atmiņu - iegūs 1%-2% varbūt. Ko tas dod nedēļas kontekstā? 1-2 stundas. Izklausās labi - "algoritms tiek ar uzdevumu galā par 2 stundām ātrāk!". Bet tie vēl joprojām ir 1%-2%. Tai pat laikā pielabojot algoritmus, nevis darbu ar atmiņu, var dabūt nevis 1%-2%, bet 1 nedēļas laikā atrisināt leveli 1 minūtē. Vot i sēdi un domā, ko darīt - nodarboties ar mikrooptimizācijām vai paskatīties uz to lietu globālāk.

Nesaku, protams, ka arī Tavā gadījumā uz algoritmu rēķina var dabūt "1 minūti 1 nedēļas vietā", bet kaut kā grūti noticēt, ka mikrooptimizācijas (<1% uzlabojumi) ir pēdējais, ko vēl var nooptimizēt.

Link to comment
Share on other sites

Baigais Janka
(labots)

Vienkārši - kernelis tiešām ir nooptimizēts līdz nelabumam :) Tāpēc pie viņa darbs prakstiski tiek pabeigts, un pāreju uz citu prožektu, citam monstram ar 728 (laikam :) kodoliem softus rakstīt. Vot, tur viss i totāli jēls...

Labots - Baigais Janka
Link to comment
Share on other sites

Inspektors Caps

Patiesība ir tāda, ka tad, kad softā iespējamās performances uzlabojums ir atlicis mazāks par 1%, tad ir īstais brīdis uzlabot hardware, nevis ieviest megabrīnumus un potenciālus bugus softā dēļ overengineering.
 

Link to comment
Share on other sites

Baigais Janka

Nu, hardware tak tiek ieviests :) Tāpēc jau traušos uz jauno projektu, tur domājams būs interesanti - uzdevumu sadale pa kodoliem, utt., utjpr.

Link to comment
Share on other sites

Kur tev tādi darbi notiekās, ja nav noslēpums?

Link to comment
Share on other sites

Baigais Janka

Nokia Siemens Networks prožekti - konkrēti es ņemos ar kastēm, kas nodrošina mobīlā izeju internetā. Vecā bija tā saucamā 3.75 G, a vot šitas jaunā projekta nezvērs - 4G. 32 kodolu CPU, uz dēļa 2 CPU, kastē sabāž kādus 12 dēļus, daile :)

Link to comment
Share on other sites

Izveido kontu, vai pieraksties esošajā, lai komentētu

Jums ir jābūt šī foruma biedram, lai varētu komentēt tēmas

Izveidot jaunu kontu

Piereģistrējies un izveido jaunu kontu, tas būs viegli!

Reģistrēt jaunu kontu

Pierakstīties

Jums jau ir konts? Pierakstieties tajā šeit!

Pierakstīties tagad!
 Share

×
×
  • Izveidot jaunu...