Dynamische Variablen

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

 

walski

Ehemaliger Admin

Betreff: Dynamische Variablen

BeitragFr, Jun 25, 2004 2:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Moin,
als Grundstock für meinen geplanten Script-Interpreter hier nuneinmal eine Verwaltung dynamischer Variablen.
Sie ist super frisch, kaum debuggt und dürfte daher eher etwas zum lernen oder anschauen sein Smile
Aber ich freue mich natürlich über euer Feedback und über jeden Bugbericht.

Das ganze ist eigentlich eine simple Type-Lösung, die ich allerdings um eine Art Cache erweitert habe.
Dieser soll dazu dienen, das bei großen Datenbeständen nicht immer alle Variablen durchgegangen werden müssen, sondern das die häufigst aufgerufenen Variablen schneller zu erreichen sind.
Sprich: Man hat 100 Variablen, davon nutzt man 95 nur 3 mal, die letzten 5 aber in fast jeder Schleife. Es wäre also ziemlich verschwenderisch jeden Schleifendurchgang alle 100 Einträge durchzugehen, nur um die fünf Variablen herauszufinden, die man eh jede Schleife wieder braucht.

Ich habe also eine zweite Typelist mit fester Länge, in der genau diese häufig aufgerufenen Variablen verzeichnet sind und schnell abgerufen werden können, da der Cache eben viel kleiner ist als die gesamte Liste aller Variablen.

Die momentan genutze Methode um die "häufig genutzen Variablen" herauszufinden ist ehr einfach und daher sicher noch verbesserungsbedürftig Smile
Ich schaue mir einfach die Zeitdifferenz der letzten fünf Aufrufe der Variable an, und je kleiner die ist, desto häufiger werden sie momentan genutzt Smile

Naja, schaut einfach selbst.

Hier erstmal die Funktionssammlung:
Code: [AUSKLAPPEN]

;oooooooooooooooooooooooooooooooo;
;        Dynamic variables       ;
;    (c) 2004 by T. Schroeder    ;
;       netkowalski@web.de       ;
;oooooooooooooooooooooooooooooooo;

;oooooooooooooooooooooooooooooooo;
; STATISTIC STUFF
; ONLY FOR DEBUG PURPOSES
Global cacheCalled,sumCalled
;oooooooooooooooooooooooooooooooo;


; The type which describes the dynamic variables
Type var

   ; The Name of the variable
   Field name$

   ; The Value of the variable as String, for taking all possible inputs
   Field value$
   
   ; A field to save the last five times of calling this variable. This is important for caching
   ; ... purposes
   Field timestamps[4]
   
   ; The idletime between the last five callings
   Field idleTime

End Type


; The type for caching often called variables
Type varCache
   
   ; Handle of the cached variable
   Field hndl
   
End Type

; the maximal idle-time which is still in the cache
Global dynVarCache_maxIdleTime

; the handle of this "max-idler"
Global dynVarCache_maxIdleHndl

; the number of items in the cache

Global dynVarCache_count

Const dynVarCache_maxItems = 10

; Function returns the handle of a variable if it's cached or 0 if it's not in the cache [INTEGER]
; Standart Input: Name of the variable [STRING]
Function varIsInCache(name$)
   
   Local tempVar.var,tempCache.varCache
   
   ; cycle through the cache
   For tempCache.varCache = Each varCache
      
      ; converting the handle of the current cache-item to a variable
      tempVar.var = Object.var( tempCache\hndl )

      ; checking the name
      If tempVar\name$ = name$ Then
         
         ; return the handle if the name matched
         Return tempCache\hndl

      EndIf
   Next
   
   ;return 0 if there was no match
   Return 0

End Function


; Function returns the handle of a variable or 0 if it's does not exists [INTEGER]
; Standart Input: Name of the variable [STRING]
Function varExists( name$ )
   
   Local tempVar.var,tempHndl

   ;oooooooooooooooooooooooooooooooo;
   ; STATISTIC STUFF
   ; ONLY FOR DEBUG PURPOSES
   sumCalled = sumCalled + 1
   ;oooooooooooooooooooooooooooooooo;
   
   ; check if the variable is in the cache
   tempHndl = varIsInCache( name$ )
   
   If Not tempHndl Then
   
      ; cycle through any variable if there was no match in the cache
      For tempVar.var = Each var
      
         If tempVar\name$ = name$ Then
         
            ; returns the  handle of the current variable if the name matches
            Return Handle( tempVar.var )
            
         EndIf
      Next
   
   Else
      
      ;oooooooooooooooooooooooooooooooo;
      ; STATISTIC STUFF
      ; ONLY FOR DEBUG PURPOSES
      cacheCalled = cacheCalled + 1
      ;oooooooooooooooooooooooooooooooo;

      
      ; returns the cached handle if the variable was in the cache
      Return tempHndl
   
   EndIf
   
   ; returns 0 if the variable does not exist yet
   Return 0

End Function   

; Function for writing something to a variable [VAR]
; Standart Input: Name of the variable [STRING], Value of the variable [STRING]
Function writeVar.var( name$,value$ )
   
   Local tempVar.var,tempHndl
   
   ; check if a ariable with this name allready exists
   tempHndl = varExists( name$ )
   
   If Not tempHndl Then
      
      ; create a new variable if it does not exist yet
      tempVar.var = New var
      
      ; label the new variable with the given name
      tempVar\name$ = name$
         
   Else
      
      ; if the variable exist convert the handle to an variable-object
      tempVar.var = Object.var(tempHndl)
      
      ; update the timestamps of the variable
      handleTimestamps( tempVar.var )
      
   EndIf
   
   ; set the given value to the variable
   
   tempVar\value$ = value$
   
   Return tempVar
   
End Function

; Function for writing an integer to a variable [VAR]
; Standart Input: Name of the variable [STRING], Value of the variable [INTEGER]
Function writeVarI.var( name$,value )
   
   Return writeVar( name$,Str( value ) )
   
End Function

; Function for writing an float to a variable [VAR]
; Standart Input: Name of the variable [STRING], Value of the variable [FLOAT]
Function writeVarF.var( name$,value# )
   
   Return writeVar( name$,Str( value# ) )
   
End Function



; Function to read the value of a variable, it returns an empty string
; ... when the variable does Not exist [STRING]
; Standart Input: Name of the variable [STRING]
Function readVar$(name$)

   Local tempVar.var,tempHndl
   
   ; checks the handle of the variable
   tempHndl = varExists( name$ )
   
   If Not tempHndl Then
      
      ; if there was no variable with the given name return an empty string
      Return ""
      
   Else
   
      ; convert the returned handle to an variable-object
      tempVar.var = Object.var( tempHndl )
      
      ; update the timestamps of the variable
      
      handleTimestamps( tempVar.var )
      
      ; return the value of the variable
      Return tempVar\value$
      
   EndIf
   
End Function

; Function to return an integer value of a variable [INTEGER]
; Standart Input: Name of the variable [STRING]
Function readVarI(name$)
   
   Return Int( readVar$( name$ ) )

End Function

; Function to return an integer value of a variable [FLOAT]
; Standart Input: Name of the variable [STRING]
Function readVarF#(name$)

   Return Float( readVar$( name$ ) )
   
End Function

; Function to update the timestamps of a variable
; Standart Input: Variable to update [VAR]
Function handleTimestamps(tempVar.var)
   
   Local i
   
   ; shift the older timestamps up
   For i = 0 To 3
      
      tempVar\timestamps[ i ] = tempVar\timestamps[ i + 1 ]

   Next
   
   ; rewrite the last timestamp with the current time

   tempVar\timestamps[4] = MilliSecs()
   
   ; calculates the idle time ( how long took the last five calls )
   tempVar\idleTime = tempVar\timestamps[4] - tempVar\timestamps[0]
   
   ; hands over the current variable to the cache management
   handleCache(tempVar.var)
      

End Function


; Function to check if a variable fits into the cache and then manages this assignment
; Standart Input: Variable to update [VAR]
Function handleCache(tempVar.var)
   
   Local tempCache.varCache
   
   ; updates the cache
   updateCache
   
   ; !!! here you could update the given variable, too. For optimization-processes I forbear from
   ; ... updating it and assume that this has been done before. If it's not quite sure, that this
   ; ... is done, you better update the variable if you want to prevent the cache from wrong
   ; ... results !!!
   
   If dynVarCache_count < dynVarCache_maxItems Then
   
      ; creates a new cache-item if there are not enough cached items, yet
      tempCache.varCache = New varCache
      tempCache\hndl = Handle( tempVar.var )
      
      ; raises the counter of cached items
      dynVarCache_count = dynVarCache_count + 1
      
   Else
   
      If (tempVar\idletime < dynVarCache_maxIdleTime) And ( Not varIsInCache( tempVar\name$ ) ) Then
         
         ; deletes the fewest frequented item in the cache if the current variable is more
         ; ... frequented then this item
         tempCache.varCache = Object.varCache( dynVarCache_maxIdleHndl )
         
         Delete tempCache.varCache
         
         ; create a new cache-item
         tempCache.varCache = New varCache
         tempCache\hndl = Handle( tempVar.var )
         
      EndIf
      
   EndIf
   
End Function

; Function to update the cache with the current timestamp
; Standart Input: %
Function updateCache()

   Local tempCache.varCache,tempVar.var
   
   ; resets the "maximal idle time" of the cache
   dynVarCache_maxIdleTime = -1
   
   ; cycle through any item of the cache
   For tempCache.varCache = Each varCache
   
      ; convert the current cached handle to an variable-object
      tempVar.var = Object.var( tempCache\hndl )
      
      ; recalculate the idle-time of this variable
      tempVar\idleTime = tempVar\timestamps[4] - tempVar\timestamps[0]
      
      If tempVar\idletime > dynVarCache_maxIdleTime Or dynVarCache_maxIdleTime = -1 Then

         ; sets this item as the fewest frequented item in the cache if there is no object
         ; ... assigned to this position, yet or it actually IS the fewest frequented item
         dynVarCache_maxIdleTime = tempVar\idleTime
         dynVarCache_maxIdleHndl = Handle( tempCache.varCache )
         
      EndIf
      
   Next

End Function


Und hier ein kleines Beispiel, das ihr einfach hintendran kopieren könnt.
Es simuliert in der Standart-Einstellung 1.000 Variablen, von denen pro Schleifendurchgang 8 zufällig gelesen werden, und 2 immer gleich sind, nämlich Variable 10 und 20. Dadurch erreiche ich eine Cache-Nutzung von 20 Prozent (klingt logisch, oder) Wink Was doch sehr schön ist. Bei 10.000 erreiche ich bei dieser "erzwungenen Häufung" der zwei, immer gleiche, Variablen ein 10 FPS-Plus im Gegensatz dazu, wenn wirklich 10 zufällige Variablen ausgewählt werden, der Cache scheint sich hier also bezahlt zu machen, aber wie gesagt, alles ist noch sehr frisch und ich weiß nicht, ob der Cache überhaupt Sinn macht Wink

Momentan erreiche ich in der "as it is" Einstellung und ohne Debug zwischen 160 und 195 FPS, im Schnitt sind es etwa 170.

Code: [AUSKLAPPEN]


howMuchVars = 1000
For i = 1 To howMuchVars
   If i Mod 100 = 0 Then Cls:Locate 1,1:Print "Loading: " + Str(Float(i) / (howMuchVars / 100.0)) + "%"
   writeVar(Str(i),"Var: " + Str(i))
Next

Graphics 640,480,16,2
SetBuffer BackBuffer()
SeedRnd MilliSecs()

While Not KeyHit(1)

   Cls
   
   Text 5,0,"Name:|Time 0|Times 1|Time 2|Time 3|Times 4|IdleTime"
   Text 5,220, "Current called Variables:"
   Text 550,0,"FPS: " + Str(fps)
   Text 500,20,"maxIdleTime: " + Str(dynVarCache_maxIdleTime)
   Text 5,460,Str(sumCalled) + " Variables called. " + Str(cacheCalled) + " from the cache, which makes " + Str(Float(cacheCalled) / (sumCalled / 100.0)) + "%"
   
   i = 0
   For tempCache.varCache = Each varCache
      
      tempVar.var = Object.var(tempCache\hndl)
      Text 5,20 + i,tempVar\name$ + " - " + Str(tempVar\timestamps[0]) + " - " + Str(tempVar\timestamps[1]) + " - " + Str(tempVar\timestamps[2]) + " - " + Str(tempVar\timestamps[3]) + " - " + Str(tempVar\timestamps[4]) + " : " + Str(tempVar\idleTime)
      i = i + 20
      
   Next
   
   For i = 0 To 7
      iRand = Rand(0,howMuchVars)
      bcc = cacheCalled
      a$ = readVar(Str(iRand))
      If cacheCalled > bcc Then
         Color 0,255,0
      EndIf
      Text 5,240 + i * 20,Str(i) + ": " + a$
      Color 255,255,255

   Next
   ;simulate two very frequented variables
   bcc = cacheCalled
   a$ = readVar(Str(Rand(1,5)))
   If cacheCalled > bcc Then
      Color 0,255,0
   EndIf
   Text 5,240 + 8 * 20,Str(8) + ": " + a$
   Color 255,255,255
   bcc = cacheCalled
   a$ = readVar(Str(Rand(6,10)))
   If cacheCalled > bcc Then
      Color 0,255,0
   EndIf
   Text 5,240 + 9 * 20,Str(9) + ": " + a$
   Color 255,255,255

   
   tTime = MilliSecs()
   If lastFpsTime + 1000 < tTime Then
      
      lastFpsTime = tTime
      fps = fpsCount
      fpsCount = 0

   EndIf
   
   fpsCount = fpsCount + 1
      
   Flip 0

Wend


Bitte beschwert euch nicht über den lausigen Stil des Beispiels, aber das war auch eigentlich nur für mich selbst, zum testen gedacht.
Aber da ich dachte, dass manche von euch evtl Lust haben mitzutesten: Bitte Schön! *g

Ich würde mich wirklich sehr über eure Ergebnisse (vor allem mit verschiedenen Einstellungen etc) freuen und möchte euch ermuntern, eure Meinung zu der ganzen Cache Idee zu verkünden.

Gute Nacht

walski

[EDIT]
In der Funktionssammlung haben sich zwei kleine aber bedeutende Fehler eingeschlichen, die ich nun berichtigt habe.
Außerdem habe ich das Beispiel etwas erweitert, aber kaum merklich.
[/EDIT]
buh!

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group