+get_ram_data()
+{
+ eval $LOGFS
+
+ local a_temp='' array_string=''
+
+ get_dmidecode_data
+
+ if [[ -n $DMIDECODE_DATA ]];then
+ if [[ $DMIDECODE_DATA == 'dmidecode-error-'* ]];then
+ A_MEMORY_DATA[0]=$DMIDECODE_DATA
+ # please note: only dmidecode version 2.11 or newer supports consistently the -s flag
+ else
+ IFS=$'\n'
+ A_MEMORY_DATA=( $(
+ gawk -F ':' '
+ BEGIN {
+ IGNORECASE=1
+ arrayHandle=""
+ bankLocator=""
+ clockSpeed=""
+ configuredClockSpeed=""
+ dataWidth=""
+ deviceManufacturer=""
+ devicePartNumber=""
+ deviceSerialNumber=""
+ deviceSpeed=""
+ deviceType=""
+ deviceTypeDetail=""
+ deviceSize=""
+ errorCorrection=""
+ formFactor=""
+ handle=""
+ location=""
+ locator=""
+ aArrayData[0,"maxCapacity5"]=0
+ aArrayData[0,"maxCapacity16"]=0
+ aArrayData[0,"usedCapacity"]=0
+ aArrayData[0,"maxModuleSize"]=0
+ aArrayData[0,"derivedModuleSize"]=0
+ aArrayData[0,"deviceCount5"]=0
+ aArrayData[0,"deviceCount16"]=0
+ aArrayData[0,"deviceCountFound"]=0
+ aArrayData[0,"moduleVoltage5"]=""
+ moduleVoltage=""
+ numberOfDevices=""
+ primaryType=""
+ totalWidth=""
+ use=""
+ i=0
+ j=0
+ k=0
+ bDebugger1="false"
+ dDebugger2="false"
+ bType5="false"
+ }
+ function calculateSize(data,size) {
+ if ( data ~ /^[0-9]+[[:space:]]*[GMTP]B/) {
+ if ( data ~ /GB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*GB/,"\\1",1,data) * 1024
+ }
+ else if ( data ~ /MB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*MB/,"\\1",1,data)
+ }
+ else if ( data ~ /TB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*TB/,"\\1",1,data) * 1024 * 1000
+ }
+ else if ( data ~ /PB/ ) {
+ data=gensub(/([0-9]+)[[:space:]]*TB/,"\\1",1,data) * 1024 * 1000 * 1000
+ }
+ if (data ~ /^[0-9][0-9]+$/ && data > size ) {
+ size=data
+ }
+ }
+ return size
+ }
+ /^Table[[:space:]]+at[[:space:]]/ {
+ bType5="false"
+ # we need to start count here because for testing > 1 array, and we want always to have
+ # the actual module data assigned to the right primary array, even when it is out of
+ # position in dmidecode output
+ i=0
+ j=0
+ k++
+ }
+ # {print k ":k:" $0}
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+5(,|[[:space:]])/ {
+ while ( getline && !/^$/ ) {
+ if ( $1 == "Maximum Memory Module Size" ) {
+ aArrayData[k,"maxModuleSize"]=calculateSize($2,aArrayData[k,"maxModuleSize"])
+ # print "mms:" aArrayData[k,"maxModuleSize"] ":" $2
+ }
+ if ($1 == "Maximum Total Memory Size") {
+ aArrayData[k,"maxCapacity5"]=calculateSize($2,aArrayData[k,"maxCapacity5"])
+ }
+ if ( $1 == "Memory Module Voltage" ) {
+ aArrayData[k,"moduleVoltage5"]=$2
+ }
+ }
+ aArrayData[k,"data-type"]="memory-array"
+ # print k ":data5:"aArrayData[k,"data-type"]
+ bType5="true"
+ }
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+6(,|[[:space:]])/ {
+ while ( getline && !/^$/ ) {
+ if ( $1 == "Installed Size" ) {
+ # get module size
+ aMemory[k,j,18]=calculateSize($2,0)
+ # get data after module size
+ sub(/ Connection/,"",$2)
+ sub(/^[0-9]+[[:space:]]*[MGTP]B[[:space:]]*/,"",$2)
+ aMemory[k,j,16]=$2
+ }
+ if ( $1 == "Current Speed" ) {
+ aMemory[k,j,17]=$2
+ }
+ }
+ j++
+ }
+
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+16/ {
+ arrayHandle=gensub(/Handle[[:space:]]([0-9a-zA-Z]+)([[:space:]]|,).*/,"\\1",$0)
+ while ( getline && !/^$/ ) {
+ # print $0
+ if ( $1 == "Maximum Capacity") {
+ aArrayData[k,"maxCapacity16"]=calculateSize($2,aArrayData[k,"maxCapacity16"])
+ #print "mc:" aArrayData[k,"maxCapacity16"] ":" $2
+ }
+ # note: these 3 have cleaned data in get_dmidecode_data, so replace stuff manually
+ if ( $1 == "Location") {
+ sub(/[[:space:]]Or[[:space:]]Motherboard/,"",$2)
+ location=$2
+ if ( location == "" ){
+ location="System Board"
+ }
+ }
+ if ( $1 == "Use") {
+ use=$2
+ if ( use == "" ){
+ use="System Memory"
+ }
+ }
+ if ( $1 == "Error Correction Type") {
+ errorCorrection=$2
+ if ( errorCorrection == "" ){
+ errorCorrection="None"
+ }
+ }
+ if ( $1 == "Number of Devices") {
+ numberOfDevices=$2
+ }
+ }
+ aArrayData[k,"data-type"]="memory-array"
+ # print k ":data16:"aArrayData[k,"data-type"]
+ aArrayData[k,"handle"]=arrayHandle
+ aArrayData[k,"location"]=location
+ aArrayData[k,"deviceCount16"]=numberOfDevices
+ aArrayData[k,"use"]=use
+ aArrayData[k,"errorCorrection"]=errorCorrection
+
+ # reset
+ primaryType=""
+ arrayHandle=""
+ location=""
+ numberOfDevices=""
+ use=""
+ errorCorrection=""
+ moduleVoltage=""
+
+ aDerivedModuleSize[k+1]=0
+ aArrayData[k+1,"deviceCountFound"]=0
+ aArrayData[k+1,"maxCapacity5"]=0
+ aArrayData[k+1,"maxCapacity16"]=0
+ aArrayData[k+1,"maxModuleSize"]=0
+ }
+ /^Handle .* DMI[[:space:]]+type[[:space:]]+17/ {
+ while ( getline && !/^$/ ) {
+ if ( $1 == "Array Handle") {
+ arrayHandle=$2
+ }
+ if ( $1 == "Data Width") {
+ dataWidth=$2
+ }
+ if ( $1 == "Total Width") {
+ totalWidth=$2
+ }
+ if ( $1 == "Size") {
+ # do not try to guess from installed modules, only use this to correct type 5 data
+ aArrayData[k,"derivedModuleSize"]=calculateSize($2,aArrayData[k,"derivedModuleSize"])
+ workingSize=calculateSize($2,0)
+ if ( workingSize ~ /^[0-9][0-9]+$/ ){
+ aArrayData[k,"deviceCountFound"]++
+ # build up actual capacity found for override tests
+ aArrayData[k,"usedCapacity"]=workingSize + aArrayData[k,"usedCapacity"]
+ }
+ # print aArrayData[k,"derivedModuleSize"] " dm:" k ":mm " aMaxModuleSize[k] " uc:" aArrayData[k,"usedCapacity"]
+ # we want any non real size data to be preserved
+ if ( $2 ~ /^[0-9]+[[:space:]]*[MTPG]B/ ) {
+ deviceSize=workingSize
+ }
+ else {
+ deviceSize=$2
+ }
+ }
+ if ( $1 == "Locator") {
+ # sub(/.*_/,"",$2)
+ #sub(/RAM slot #|^DIMM/, "Slot",$2)
+ sub(/RAM slot #/, "Slot",$2)
+
+ #locator=toupper($2)
+ locator=$2
+ }
+ if ( $1 == "Bank Locator") {
+ #sub(/_.*/,"",$2)
+ #sub(/RAM slot #|Channel|Chan/,"bank",$2)
+ #sub(/RAM slot #|Channel|Chan/,"bank",$2)
+ #bankLocator=toupper($2)
+ bankLocator=$2
+ }
+ if ( $1 == "Form Factor") {
+ formFactor=$2
+ }
+ if ( $1 == "Type") {
+ deviceType=$2
+ }
+ if ( $1 == "Type Detail") {
+ deviceTypeDetail=$2
+ }
+ if ( $1 == "Speed") {
+ deviceSpeed=$2
+ }
+ if ( $1 == "Configured Clock Speed") {
+ configuredClockSpeed=$2
+ }
+ if ( $1 == "Manufacturer") {
+ gsub(/(^[0]+$|Undefined.*|.*Manufacturer.*)/,"",$2)
+ deviceManufacturer=$2
+ }
+ if ( $1 == "Part Number") {
+ sub(/(^[0]+$||.*Module.*|Undefined.*)/,"",$2)
+ devicePartNumber=$2
+ }
+ if ( $1 == "Serial Number") {
+ gsub(/(^[0]+$|Undefined.*)/,"",$2)
+ deviceSerialNumber=$2
+ }
+ }
+ # because of the wide range of bank/slot type data, we will just use
+ # the one that seems most likely to be right. Some have: Bank: SO DIMM 0 slot: J6A
+ # so we dump the useless data and use the one most likely to be visibly correct
+ if ( bankLocator ~ /DIMM/ ) {
+ mainLocator=bankLocator
+ }
+ else {
+ mainLocator=locator
+ }
+ # sometimes the data is just wrong, they reverse total/data. data I believe is
+ # used for the actual memory bus width, total is some synthetic thing, sometimes missing.
+ # note that we do not want a regular string comparison, because 128 bit memory buses are
+ # in our future, and 128 bits < 64 bits with string compare
+ intData=gensub(/(^[0-9]+).*/,"\\1",1,dataWidth)
+ intTotal=gensub(/(^[0-9]+).*/,"\\1",1,totalWidth)
+ if (intData != "" && intTotal != "" && intData > intTotal ) {
+ tempWidth=dataWidth
+ dataWidth=totalWidth
+ totalWidth=tempWidth
+ }
+
+ aMemory[k,i,0]="memory-device"
+ aMemory[k,i,1]=arrayHandle
+ aMemory[k,i,2]=deviceSize
+ aMemory[k,i,3]=bankLocator
+ aMemory[k,i,4]=locator
+ aMemory[k,i,5]=formFactor
+ aMemory[k,i,6]=deviceType
+ aMemory[k,i,7]=deviceTypeDetail
+ aMemory[k,i,8]=deviceSpeed
+ aMemory[k,i,9]=configuredClockSpeed
+ aMemory[k,i,10]=dataWidth
+ aMemory[k,i,11]=totalWidth
+ aMemory[k,i,12]=deviceManufacturer
+ aMemory[k,i,13]=devicePartNumber
+ aMemory[k,i,14]=deviceSerialNumber
+ aMemory[k,i,15]=mainLocator
+
+ primaryType=""
+ arrayHandle=""
+ deviceSize=""
+ bankLocator=""
+ locator=""
+ mainLocator=""
+ mainLocator=""
+ formFactor=""
+ deviceType=""
+ deviceTypeDetail=""
+ deviceSpeed=""
+ configuredClockSpeed=""
+ dataWidth=""
+ totalWidth=""
+ deviceManufacturer=""
+ devicePartNumber=""
+ deviceSerialNumber=""
+ i++
+ }
+ END {
+ ## CRITICAL: gawk keeps changing integers to strings, so be explicit with int() in math
+ # print primaryType "," arrayHandle "," location "," maxCapacity "," numberOfDevices "," use "," errorCorrection "," maxModuleSize "," moduleVoltage
+
+ # print primaryType "," arrayHandle "," deviceSize "," bankLocator "," locator "," formFactor "," deviceType "," deviceTypeDetail "," deviceSpeed "," configuredClockSpeed "," dataWidth "," totalWidth "," deviceManufacturer "," devicePartNumber "," deviceSerialNumber "," mainLocator
+
+ for ( m=1;m<=k;m++ ) {
+ estCap=""
+ estMod=""
+ unit=""
+ altCap=0
+ workingMaxCap=int(aArrayData[m,"maxCapacity16"])
+
+ if ( bDebugger1 == "true" ){
+ print ""
+ print "count: " m
+ print "1: mmods: " aArrayData[m,"maxModuleSize"] " :dmmods: " aArrayData[m,"derivedModuleSize"] " :mcap: " workingMaxCap " :ucap: " aArrayData[m,"usedCapacity"]
+ }
+ # 1: if max cap 1 is null, and max cap 2 not null, use 2
+ if ( workingMaxCap == 0 ) {
+ if ( aArrayData[m,"maxCapacity5"] != 0 ) {
+ workingMaxCap=aArrayData[m,"maxCapacity5"]
+ }
+ }
+ if ( aArrayData[m,"deviceCount16"] == "" ) {
+ aArrayData[m,"deviceCount16"] = 0
+ }
+ if ( bDebugger1 == "true" ){
+ print "2: mmods: " aArrayData[m,"maxModuleSize"] " :dmmods: " aArrayData[m,"derivedModuleSize"] " :mcap: " workingMaxCap " :ucap: " aArrayData[m,"usedCapacity"]
+ }
+ # 2: now check to see if actually found module sizes are > than listed max module, replace if >
+ if (aArrayData[m,"maxModuleSize"] != 0 && aArrayData[m,"derivedModuleSize"] != 0 && int(aArrayData[m,"derivedModuleSize"]) > int(aArrayData[m,"maxModuleSize"]) ) {
+ aArrayData[m,"maxModuleSize"]=aArrayData[m,"derivedModuleSize"]
+ estMod=" (est)"
+ }
+ aArrayData[m,"maxModuleSize"]=int(aArrayData[m,"maxModuleSize"])
+ aArrayData[m,"derivedModuleSize"]=int(aArrayData[m,"derivedModuleSize"])
+ aArrayData[m,"usedCapacity"]=int(aArrayData[m,"usedCapacity"])
+ workingMaxCap=int(workingMaxCap)
+
+ # note: some cases memory capacity == max module size, so one stick will fill it
+ # but I think only with cases of 2 slots does this happen, so if > 2, use the count of slots.
+ if ( bDebugger1 == "true" ){
+ print "3: fmod: " aArrayData[m,"deviceCountFound"] " :modc: " aArrayData[m,"deviceCount16"] " :maxc1: " aArrayData[m,"maxCapacity5"] " :maxc2: " aArrayData[m,"maxCapacity16"]
+ }
+ if (workingMaxCap != 0 && ( aArrayData[m,"deviceCountFound"] != 0 || aArrayData[m,"deviceCount16"] != 0 ) ) {
+ aArrayData[m,"deviceCount16"]=int(aArrayData[m,"deviceCount16"])
+ ## first check that actual memory found is not greater than listed max cap, or
+ ## checking to see module count * max mod size is not > used capacity
+ if ( aArrayData[m,"usedCapacity"] != 0 && aArrayData[m,"maxCapacity16"] != 0 ) {
+ if ( aArrayData[m,"usedCapacity"] > workingMaxCap ) {
+ if ( aArrayData[m,"maxModuleSize"] != 0 &&
+ aArrayData[m,"usedCapacity"] < aArrayData[m,"deviceCount16"] * aArrayData[m,"maxModuleSize"] ) {
+ workingMaxCap=aArrayData[m,"deviceCount16"] * aArrayData[m,"maxModuleSize"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "A"
+ }
+ }
+ else if ( aArrayData[m,"derivedModuleSize"] != 0 &&
+ aArrayData[m,"usedCapacity"] < aArrayData[m,"deviceCount16"] * aArrayData[m,"derivedModuleSize"] ) {
+ workingMaxCap=aArrayData[m,"deviceCount16"] * aArrayData[m,"derivedModuleSize"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "B"
+ }
+ }
+ else {
+ workingMaxCap=aArrayData[m,"usedCapacity"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "C"
+ }
+ }
+ }
+ }
+ # note that second case will never really activate except on virtual machines and maybe
+ # mobile devices
+ if ( estCap == "" ) {
+ # do not do this for only single modules found, max mod size can be equal to the array size
+ if ( ( aArrayData[m,"deviceCount16"] > 1 && aArrayData[m,"deviceCountFound"] > 1 ) &&
+ ( workingMaxCap < aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCount16"] ) ) {
+ workingMaxCap = aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCount16"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "D"
+ }
+ }
+ else if ( ( aArrayData[m,"deviceCountFound"] > 0 ) &&
+ ( workingMaxCap < aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCountFound"] ) ) {
+ workingMaxCap = aArrayData[m,"derivedModuleSize"] * aArrayData[m,"deviceCountFound"]
+ estCap=" (est)"
+ if ( bDebugger1 == "true" ){
+ print "E"
+ }
+ }
+ ## handle cases where we have type 5 data: mms x device count equals type 5 max cap
+ # however do not use it if cap / devices equals the derived module size
+ else if ( aArrayData[m,"maxModuleSize"] > 0 &&
+ ( aArrayData[m,"maxModuleSize"] * aArrayData[m,"deviceCount16"] == aArrayData[m,"maxCapacity5"] ) &&
+ aArrayData[m,"maxCapacity5"] != aArrayData[m,"maxCapacity16"] &&
+ aArrayData[m,"maxCapacity16"] / aArrayData[m,"deviceCount16"] != aArrayData[m,"derivedModuleSize"] ) {
+ workingMaxCap = aArrayData[m,"maxCapacity5"]
+ altCap=aArrayData[m,"maxCapacity5"] # not used
+ estCap=" (check)"
+ if ( bDebugger1 == "true" ){
+ print "F"
+ }
+ }
+ }
+ }
+ altCap=int(altCap)
+ workingMaxCap=int(workingMaxCap)
+ if ( bDebugger1 == "true" ){
+ print "4: mmods: " aArrayData[m,"maxModuleSize"] " :dmmods: " aArrayData[m,"derivedModuleSize"] " :mcap: " workingMaxCap " :ucap: " aArrayData[m,"usedCapacity"]
+ }
+ # some cases of type 5 have too big module max size, just dump the data then since
+ # we cannot know if it is valid or not, and a guess can be wrong easily
+ if ( aArrayData[m,"maxModuleSize"] != 0 && workingMaxCap != "" &&
+ ( aArrayData[m,"maxModuleSize"] > workingMaxCap ) ){
+ aArrayData[m,"maxModuleSize"] = 0
+ # print "yes"
+ }
+ if ( bDebugger1 == "true" ){
+ print "5: dms: " aArrayData[m,"derivedModuleSize"] " :dc: " aArrayData[m,"deviceCount16"] " :wmc: " workingMaxCap
+ }
+ ## prep for output ##
+ if (aArrayData[m,"maxModuleSize"] == 0 ){
+ aArrayData[m,"maxModuleSize"]=""
+ # ie: 2x4gB
+ if ( estCap == "" && int(aArrayData[m,"derivedModuleSize"]) > 0 &&
+ workingMaxCap > ( int(aArrayData[m,"derivedModuleSize"]) * int(aArrayData[m,"deviceCount16"]) * 4 ) ) {
+ estCap=" (check)"
+ if ( bDebugger1 == "true" ){
+ print "G"
+ }
+ }
+ }
+ else {
+ # case where listed max cap is too big for actual slots x max cap, eg:
+ # listed max cap, 8gb, max mod 2gb, slots 2
+ if ( estCap == "" && aArrayData[m,"maxModuleSize"] > 0 ) {
+ if ( int(workingMaxCap) > int(aArrayData[m,"maxModuleSize"]) * aArrayData[m,"deviceCount16"] ) {
+ estCap=" (check)"
+ if ( bDebugger1 == "true" ){
+ print "H"
+ }
+ }
+ }
+ if (aArrayData[m,"maxModuleSize"] > 1023 ) {
+ aArrayData[m,"maxModuleSize"]=aArrayData[m,"maxModuleSize"] / 1024 " GB"
+ }
+ else {
+ aArrayData[m,"maxModuleSize"]=aArrayData[m,"maxModuleSize"] " MB"
+ }
+ }
+ if ( aArrayData[m,"deviceCount16"] == 0 ) {
+ aArrayData[m,"deviceCount16"] = ""
+ }
+ if (workingMaxCap != 0 ) {
+ if ( workingMaxCap < 1024 ) {
+ workingMaxCap = workingMaxCap
+ unit=" MB"
+ }
+ else if ( workingMaxCap < 1024000 ) {
+ workingMaxCap = workingMaxCap / 1024
+ unit=" GB"
+ }
+ else if ( workingMaxCap < 1024000000 ) {
+ workingMaxCap = workingMaxCap / 1024000
+ unit=" TB"
+ }
+ # we only want a max 2 decimal places, this trick gives 0 to 2
+ workingMaxCap=gensub(/([0-9]+\.[0-9][0-9]).*/,"\\1",1,workingMaxCap)
+ workingMaxCap = workingMaxCap unit estCap
+
+ }
+ else {
+ workingMaxCap == ""
+ }
+
+ print aArrayData[m,"data-type"] "," aArrayData[m,"handle"] "," aArrayData[m,"location"] "," workingMaxCap "," aArrayData[m,"deviceCount16"] "," aArrayData[m,"use"] "," aArrayData[m,"errorCorrection"] "," aArrayData[m,"maxModuleSize"] estMod "," aArrayData[m,"voltage5"]
+ # print device rows next
+ for ( j=0;j<=100;j++ ) {
+ if (aMemory[m,j,0] != "" ) {
+ unit=""
+ workingSize=aMemory[m,j,2]
+ if ( workingSize ~ /^[0-9]+$/ ) {
+ workingSize=int(workingSize)
+ if ( workingSize < 1024 ) {
+ workingSize = workingSize
+ unit=" MB"
+ }
+ else if ( workingSize < 1024000 ) {
+ workingSize = workingSize / 1024
+ unit=" GB"
+ }
+ else if ( workingSize < 1024000000 ) {
+ workingSize = workingSize / 1024000
+ unit=" TB"
+ }
+ # we only want a max 2 decimal places, this trick gives 0 to 2
+ workingSize=gensub(/([0-9]+\.[0-9][0-9]).*/,"\\1",1,workingSize)
+ workingSize = workingSize unit
+ }
+ print aMemory[m,j,0] "," aMemory[m,j,1] "," workingSize "," aMemory[m,j,3] "," aMemory[m,j,4] "," aMemory[m,j,5] "," aMemory[m,j,6] "," aMemory[m,j,7] "," aMemory[m,j,8] "," aMemory[m,j,9] "," aMemory[m,j,10] "," aMemory[m,j,11] "," aMemory[m,j,12] "," aMemory[m,j,13] "," aMemory[m,j,14] "," aMemory[m,j,15] "," aMemory[m,j,16] "," aMemory[m,j,17]
+ }
+ else {
+ break
+ }
+ }
+ }
+ }' <<< "$DMIDECODE_DATA" ) )
+ fi
+ fi
+ IFS="$ORIGINAL_IFS"
+ a_temp=${A_MEMORY_DATA[@]}
+
+ # echo "${a_temp[@]}"
+ log_function_data "A_MEMORY_DATA: $a_temp"
+
+ eval $LOGFE
+}
+