what is "sw $fp($sp)" mean in MIPS - cpu-architecture

I have an assignment in computer organization class.
This is part of factorial recursion code in MIPS
main:
# prolog
sub $sp, $sp, 4
sw $_ra_, ($sp)
sub $sp, $sp, 4
sw $_fp_, ($sp)
sub $fp, $sp, _8_
move $sp, $fp
In this code, I know the meaning of "sub $sp, $sp, 4" ,store $ra
and store frame pointer under the $ra register.However, I can not understand the codes "sw $fp,($sp)" , "sub $fp, $sp,8" and
"move $sp, $fp".

For the instruction "sw $fp,($sp)" sw means store word , you are storing a word in memory.Basically you are sending the contents of $fp into a memory address contained in the register $sp with zero offset.
For the instruction "sub $fp, $sp,8" you are subtracting 8 from the contents of the register $sp and you are taking the result in the register $fp.
For "move $sp, $fp" you are simply moving contents of register $fp into register $sp.

Related

Error when extracting words offset in perl

I have a program that read tow files, the first file contain terms (one, or multiterms) seprated by semicolon (; ), the second file contain text, the goal is to determine the offset of the terms in the first file!
My program begin well fluctuating vacuum (correct offsset extracted 2 20, also 45 59 for quantum fields) , but when extracting the offset for example for terms nuclear physics (correct ofsset 396 411) my code generate 399 414! or Fermionic fields (my code generate 138 154) but the correct is 135 151
The code used is:
#!/usr/bin/perl
use strict;use warnings;
my #a = ();
my #b = ();
my #aa = ();
my $l=0;
my $v=1;
my $g=0;
my $kh;
my $ligne2;
my $texte;
open(FICC, $ARGV[0]);
print "choose the name of the file\n";
my $fic = <STDIN>;
open(FIC1, ">$fic");
while (<FICC>) {
my $ligne2=$_;
$a[$l]=$ligne2;
$l++;
}
my $aa;
my $ligne;
my $rep = "C:\\scienceie2017_train\\train2";
opendir(REP,$rep) or die "E/S : $!\n";
foreach my $kh (#a) {
chomp($kh);
if ($kh=~/.*\.txt/) {
$texte=$kh;
#print "$kh";
print FIC1 "$texte";
}
#aa=split(/;/,$kh);
#$u++;
while(defined(my $fic=readdir REP)){
my $f="${rep}\\$texte";
open FIC, "$f" or warn "$f E/S: $!\n";
while(<FIC>){
$ligne = $_;
chomp($ligne);
#print FIC1 "#aa";
foreach my $che (#aa) {
$che =~ s/^\s+//;
$che =~ s/\s+$//;
if ($ligne =~/\Q$che\E/) {
print FIC1 "T$v\tTask $-[0] $+[0]\t$che\n";
$v++;
}
}
$v = 1;
}
print FIC1 "\n";
close FIC;
goto che
}
che:
}
The text is:
A fluctuating vacuum is a general feature of quantum fields, of which the free Maxwell field considered in  [1–12] is but one example. Fermionic fields such as that describing the electron, also undergo vacuum fluctuations, consequently one expects to find Casimir effects associated with such fields whenever they are confined in some way. Such effects were first investigated in the context of nuclear physics, within the so-called “MIT bag model” of the nucleon  [13]. In the bag-model one envisages the nucleon as a collection of fermionic fields describing confined quarks. These quarks are subject to a boundary condition at the surface of the ‘bag’ that represents the nucleon’s surface. Just as in the electromagnetic case, the bag boundary condition modifies the vacuum fluctuations of the field, which results in the appearance of a Casimir force  [14–18]. This force, although very weak at a macroscopic scale, can be significant on the small length scales encountered in nuclear physics. It therefore has important consequences for the physics of the bag-model nucleon  [19].
The extracted terms are:
fluctuating vacuum;general feature;quantum fields;free Maxwell;free Maxwell field;Maxwell;Maxwell field;Maxwell field;Maxwell field;field considered in ;considered in ;1–12;Fermionic fields;vacuum fluctuations;Casimir;Casimir effects;Casimir effects;Casimir effects;such fields;Such effects;nuclear physics;so-called “MIT;so-called “MIT bag;“MIT bag;“MIT bag model”;bag model”;fermionic fields;fermionic fields describing;boundary condition;nucleon’s surface;electromagnetic case;bag boundary;bag boundary condition;boundary condition;vacuum fluctuations;Casimir;Casimir force ;force ;14–18;macroscopic scale;small length;small length scales;length scales;nuclear physics;important consequences;bag-model nucleon ;
You must open your filesin UTF8
reaplce
open FIC, "$f" or warn "$f E/S: $!\n";
by
open FIC, "<:encoding(UTF-8)", "$f" or warn "$f E/S: $!\n";
I'm not clear on your code, but when I run your provided data with my code, I get these results.
The 2 variables #- and #+, ($-[0] and $+[0]) are described in the Variables-related-to-regular-expressions. (LAST_MATCH_START & LAST_MATCH_END)
My code:
#!/usr/bin/perl
use strict;
use warnings;
my $s = 'A fluctuating vacuum is a general feature ... (rest of line)';
my #terms = split /;/, 'fluctuating vacuum;Fermionic fields;nuclear physics;bag-model nucleon';
for my $term (#terms) {
while ($s =~ /$term/g) {
print "$-[0] - $+[0] $term\n";
}
}
Output:
2 - 20 fluctuating vacuum
135 - 151 Fermionic fields
396 - 411 nuclear physics
983 - 998 nuclear physics
1063 - 1080 bag-model nucleon
#!/usr/bin/perl
$string = "A fluctuating vacuum is a general feature of quantum fields, of which the free Maxwell field considered in [1–12] is but one example. Fermionic fields such as that describing the electron, also undergo vacuum fluctuations, consequently one expects to find Casimir effects associated with such fields whenever they are confined in some way. Such effects were first investigated in the context of nuclear physics, within the so-called “MIT bag model” of the nucleon [13]. In the bag-model one envisages the nucleon as a collection of fermionic fields describing confined quarks. These quarks are subject to a boundary condition at the surface of the ‘bag’ that represents the nucleon’s surface. Just as in the electromagnetic case, the bag boundary condition modifies the vacuum fluctuations of the field, which results in the appearance of a Casimir force [14–18]. This force, although very weak at a macroscopic scale, can be significant on the small length scales encountered in nuclear physics. It therefore has important consequences for the physics of the bag-model nucleon [19].";
#extracted_terms = ( "fluctuating vacuum", "Fermionic fields", "nuclear physics", "bag-model nucleon" );
for my $term ( #extracted_terms )
{
$position = index $string, $term;
printf ( "%s, %s\n", $position, $position + length($term) );
}

Perl: printing lines in specific position in a file using a while loop

I started a while loop as such:
open(INFO, "+<$file") or die("Could not open file.\n");
while(defined ($line=<INFO>)){
last if ($line=~/^.end a/);
if ($line=~/^.a/){
print INFO "inside a\n";
print INFO "still inside a\n";
}
}
Here, we have a file called INFO which is stated as such:
1
2
3
4
.a
x
y
z
.end a
Now after the above while loop, what I found, the printing inside INFO is from the beginning of its file, which is as such:
inside a
still inside a
3
4
.a
x
y
z
.end a
What I wanted to do is: I want to add line after the ".a" not modifying the lines from the beginning, its hampering the file.
1
2
3
4
.a
inside a
still inside a
x
y
z
.end a
Please help me to find out the solution of this simple problem.
thanks.
Please read: perlfaq5 - How do I change, delete, or insert a line in a file, or append to the beginning of a file?
It's not possible to modify a file in place unless you're working with fixed width records.
To insert lines like your trying to do, you ultimately have to create a new file and process the old file line by line.
In this case, I'd recommend using $INPLACE_EDIT to handle the creating of the new file for you. However, there are other methods demonstrated in the above reference.
use strict;
use warnings;
use autodie;
my $file = '...';
local #ARGV = $file;
local $^I = '.bak';
while (<>) {
print;
if (/^\.a/) {
print "inside a\n";
print "still inside a\n";
}
}
#unlink "$file$^I"; # Optionally delete backup

Modifying a perl script

I'm kinda brand new to perl (well programming in general), and have been presented with a perl script (Id_script3.pl).
Code in question from Id_script3.pl:
# main sub
{ # closure
# keep %species local to sub-routine but only init it once
my %species;
sub _init {
open my $in, '<', 'SpeciesId.txt' or die "could not open SpeciesId.txt: $!";
my $spec;
while (<$in>) {
chomp;
next if /^\s*$/; # skip blank lines
if (m{^([A-Z])\s*=\s*(\d+(?:\.\d)?)(?:\s+AND\s+(\d+(?:\.\d)?))?$}) {
# handle letter = lines
$species{$spec}{$1} = [$2];
push #{$species{$spec}{$1}}, $3 if $3;
} else {
# handle species name lines
$spec = $_;
$len = length($spec) if (length($spec) > $len);
}
}
close $in;
}
sub analyze {
my ($masses) = #_;
_init() unless %species;
my %data;
# loop over species entries
SPEC:
foreach my $spec (keys %species) {
# loop over each letter of a species
LTR:
foreach my $ltr (keys %{$species{$spec}}) {
# loop over each mass for a letter
foreach my $mass (#{$species{$spec}{$ltr}}) {
# skip to next letter if it is not found
next LTR unless exists($masses->{$mass});
}
# if we get here, all mass values were found for the species/letter
$data{$spec}{cnt}++;
}
}
The script requires a modification, in which 'SpeciesId3.txt' will be used instead of the 'SpeciesId.txt' which is currently used by the script.
There is a slight difference between the two files, so a slight modification would need to be made to the script for it to function; the difference being that SpeciesId3.txt contains no letters (A =, B =, C =) and simply a (much) longer list of values as compared to the original 'SpeciesId.txt'.
SpeciesId.txt:
African Elephant
B = 1453.7
C = 1577.8
D = 2115.1
E = 2808.4
F = 2853.5 AND 2869.5
G = 2999.4 AND 3015.4
Indian Elephant
B = 1453.7
C = 1577.8
D = 2115.1
E = 2808.4
F = 2853.5 AND 2869.5
G = 2999.4 AND 3015.4
Rabbit
A = 1221.6 AND 1235.6
B = 1453.7
C = 1592.8
D = 2129.1
E = 2808.4
F = 2883.5 AND 2899.5
G = 2957.4 AND 2973.4
SpeciesID3.txt (File to be used/script to be modified for:)
African Elephant
826.4
836.4
840.4
852.4
858.4
886.4
892.5
898.5
904.5
920.5
950.5
1001.5
1015.5
1029.5
1095.6
1105.6
Indian Elephant
835.4
836.4
840.5
852.4
868.4
877.4
886.4
892.5
894.5
898.5
908.5
920.5
950.5
1095.6
1105.6
1154.6
1161.6
1180.7
1183.6
1189.6
1196.6
1201.6
1211.6
1230.6
1261.6
1267.7
Rabbit
817.5
836.4
852.4
868.5
872.4
886.4
892.5
898.5
908.5
950.5
977.5
1029.5
1088.6
1095.6
1105.6
1125.5
1138.6
1161.6
1177.6
1182.6
1201.6
1221.6
1235.6
1267.7
1280.6
1311.6
1332.7
1378.5
1437.7
1453.7
1465.7
1469.7
As you can see, the letters (A =, B = ) have been lost for SpeciesID3.txt.
I've tried a couple of attempted "work-arounds" but am yet to write one that works.
Many Thanks,
Stephen.
Well, I don't know if I would consider keeping that script, as it looks rather messy, using script-globals inside subroutines, and strange labels. Here's a method you might like to consider, using Perl's paragraph mode by setting the input record separator $/ to the empty string.
This is a bit clunky since chomp cannot remove newlines from hash keys, so I used a do block to compensate. do { ... } works like a subroutine and returns the value of its last executed statement, in this case returns the elements of the array.
use strict;
use warnings;
use Data::Dumper;
local $/ = ""; # paragraph mode
my %a = do { my #x = <DATA>; chomp(#x); #x; }; # read the file, remove newlines
$_ = [ split ] for values %a; # split numbers into arrays
print Dumper \%a; # print data structure
__DATA__
African Elephant
826.4
836.4
840.4
852.4
858.4
886.4
892.5
898.5
904.5
920.5
950.5
1001.5
1015.5
1029.5
1095.6
1105.6
Indian Elephant
835.4
836.4
840.5
852.4
868.4
877.4
886.4
892.5
894.5
898.5
908.5
920.5
950.5
1095.6
1105.6
1154.6
1161.6
1180.7
1183.6
1189.6
1196.6
1201.6
1211.6
1230.6
1261.6
1267.7
Rabbit
817.5
836.4
852.4
868.5
872.4
886.4
892.5
898.5
908.5
950.5
977.5
1029.5
1088.6
1095.6
1105.6
1125.5
1138.6
1161.6
1177.6
1182.6
1201.6
1221.6
1235.6
1267.7
1280.6
1311.6
1332.7
1378.5
1437.7
1453.7
1465.7
1469.7
Output:
$VAR1 = {
'Rabbit' => [
'817.5',
'836.4',
'852.4',
'868.5',
'872.4',
'886.4',
'892.5',
'898.5',
'908.5',
'950.5',
'977.5',
'1029.5',
'1088.6',
'1095.6',
'1105.6',
'1125.5',
'1138.6',
'1161.6',
'1177.6',
'1182.6',
'1201.6',
'1221.6',
'1235.6',
'1267.7',
'1280.6',
'1311.6',
'1332.7',
'1378.5',
'1437.7',
'1453.7',
'1465.7',
'1469.7'
],
'Indian Elephant' => [
'835.4',
'836.4',
'840.5',
'852.4',
'868.4',
'877.4',
'886.4',
'892.5',
'894.5',
'898.5',
'908.5',
'920.5',
'950.5',
'1095.6',
'1105.6',
'1154.6',
'1161.6',
'1180.7',
'1183.6',
'1189.6',
'1196.6',
'1201.6',
'1211.6',
'1230.6',
'1261.6',
'1267.7'
],
'African Elephant' => [
'826.4',
'836.4',
'840.4',
'852.4',
'858.4',
'886.4',
'892.5',
'898.5',
'904.5',
'920.5',
'950.5',
'1001.5',
'1015.5',
'1029.5',
'1095.6',
'1105.6'
]
};
As you can see from this rather verbose output, the result is a hash with animals as keys, and your numbers as values. As long as you can rely on the names and numbers being separated by at least two consecutive newlines, and there are no arbitrary newlines inside the data, this method will do the trick.
if (m{^([A-Z])\s*=\s*(\d+(?:\.\d)?)(?:\s+AND\s+(\d+(?:\.\d)?))?$}) {
This line contains a regular expression which looks for an uppercase letter [A-Z] followed by an equals sign with optional whitespace on either side \s*=\s*. You basically just want to remove that prefix and simply match a number (\d+(?:\.\d)?).
Because $1, $2, $3 are numbered starting from the leftmost opening parenthesis, the number you want will be in $1 now. (Parentheses with ?: are non-capturing, and don't count.)
You also need to change the variable %species so that its keys are species names and its values simply a list of numbers (the extracted observations).
So:
if (m{^(\d+(?:\.\d)?)$}) {
push ${$species{$spec}}, $1;
}
The analyze subroutine needs to be similarly adapted (the LTR level is basically gone now).

calculating velocity from massive simulation data

I have simulation data for the velocity of water molecules. The format of the data is as below. I would like to describe the format of the data for clarity purposes, and it easily would lead to what I want to calculate.
A water molecule is made of three atoms: Oxygen(O) and two Hydrogen (H). Here I would name them O, H1, and H2.
The data below starts with line title 0 and the number 4335, saying it contains 4335 atoms (4335/3 = 1445 water molecules).
The first three numbers starting from the third row ( 0.0923365 0.0341984 -0.1248516 ) representing velocity for oxygen (O) atom at three Cartesian directions Ox, Oy, Oz. The next three numbers, in the same row representing velocities for hydrogen (H1) ==> H1x, H1y, H1z. And finally the first three numbers in fourth row representing velocities for hydrogen (H2) ==> H2x,H2y,H2z. finally, the following three numbers in the same fourth row representing velocities for oxygen atom.
These sequence is goes on for all 4335 atoms in 2170 lines including the top two lines in the data file and it repeats for the following section starting from title 1.
title 0
4335 2.0001000e+04
0.0923365 0.0341984 -0.1248516 -0.8946258 1.6688854 0.8259304
0.2890579 0.8051153 -1.5612963 0.0625492 -0.1361579 0.2869132
0.2343408 -0.0665305 1.0745378 -0.8375892 0.6953992 0.5149021
-0.1628550 0.0131844 0.0688080 0.2429340 0.2168210 -0.0289806
-0.3677613 0.2054004 -0.1511643 -0.3487551 -0.1454157 0.0801884
-0.9039297 -0.0682939 -0.2337404 -0.5605327 -0.0369157 0.2243892
-0.3100274 -0.2673132 -0.2093299 0.1975043 -0.4572202 -0.8410826
-0.6995287 -0.4123909 0.0649209 -0.1910519 0.2289656 0.2443295
-0.0279093 0.5790939 -0.0104249 -1.1961776 -0.5387340 0.1445187
-0.3188485 0.3789352 -0.0112114 0.7831523 0.6043882 -0.7131590
-0.7214440 -0.5358508 -0.3035673 -0.1549275 -0.1402387 -0.0101964
-0.2027608 1.5107149 0.2963312 -1.5104872 -0.1554981 -1.3323215
0.1097982 -0.1553742 0.3803437 0.0816858 0.0265007 0.4215823
0.1157368 0.2100116 0.4712551 0.1799426 -0.1260255 -0.2131755
0.1811777 -0.9442581 -0.6036636 0.9681703 -0.1523646 -0.3502441
0.0976771 0.0019619 -0.1832204 -0.0055989 0.2701100 -0.4416720
0.8496723 0.4070951 -0.0819204 0.1156806 -0.1619873 -0.0016126
-0.4051959 0.4263505 -0.9460036 0.4412067 0.1002270 0.5864405
-0.3831136 0.3240860 -0.0005143 -0.5667163 0.2618876 0.0103317
-0.6442209 0.3965833 -0.0778050 -0.2404238 -0.1339887 -0.1662417
0.3421198 0.7480828 -1.8316993 -0.4454920 -0.0499657 -0.1951254
-0.2895359 -0.1934811 -0.2674928 0.1255802 1.3522828 -0.2829485
-0.4129106 -0.6842645 -1.0147657 -0.1278501 -0.0597648 -0.1478294
-0.2519974 0.0665314 -0.0690079 -0.0480210 -0.1179547 -0.2091919
-0.1942484 0.2583650 -0.0734658 -0.1216313 0.5158040 -0.0676843
-0.3063602 0.8148463 -0.1959571 -0.1009838 -0.3394633 -0.0866587
.
. (goes on until line 2170)
.
0.1028815 -0.0844088 -0.2156557 -0.1698745 -0.2018967 -0.3863209
0.1793070 -0.1005802 0.1800752 -0.1404713 0.2216020 0.2236271
0.5192825 -0.7398186 0.0418758 0.0347715 -0.3457840 -0.1300237
-0.3089482 1.1125441 -0.4020403 0.2739744 -0.9062766 0.0012294
0.1498538 0.0883857 -0.0094638 0.0963565 -1.1027019 0.0115313
-0.0432824 0.3330713 0.0304943
title 1
4335 2.0002000e+04
-0.2082078 0.1774843 -0.1023302 -0.1100437 0.5973607 1.0627041
-0.2216015 0.0448885 -0.8415924 0.1691296 0.6008261 -0.0373434
0.9387534 -0.3642305 0.6756270 -0.6000357 0.6632088 1.0567899
-0.3234407 -0.1781680 -0.1936070 -0.4799916 -0.1522612 -0.2347461
0.1045985 0.1999704 -0.1482928 -0.0439331 0.0413923 0.1605458
0.3403952 -0.2012104 0.4851457 -0.9665228 0.2202362 0.0046218
.
. (goes on until line 2170)
.
What I want to calculate is the resultant velocity for each molecule and I would like to do this using Perl. The algorithm goes in this way.
First store the velocities for oxygen (O) and hydrogens (H1 & H2) in Ox,Oy,Oz, H1x,H1y,H1z and H2x,H2y,H2z respectively.
Next we define:
velocity_x = Ox + Hx + Hx
velocity_y = Oy + Hy + Hy
velocity_z = Oz + Hz + Hz
Finally calculate
resultant_velocity = sqrt(velocity_x**2 + velocity_y**2 + velocity_z**2)
and store the "resultant_velocity" into new file (the file should be title_0.dat). And the program shall calculate the velocities starting from title 1 until title 200 in the file.
I am a newbie at Perl, but I would like to do this operation in Perl since I find that it is very interesting. I can write simple "read and write" operations in Perl but found no idea how to split and assign the values to the variables and carryout the calculation though the calculation is high school standard.
#!/usr/bin/perl -w
$data_file="malto.dat";
open(DAT, $data_file) || die("Could not open file!");
#raw_data=<DAT>;
close(DAT);
while(<#raw_data>){
#columns=split /\s+/,$_;
if($columns[0]=~ m/ATOM/){
print "$columns[5], $columns[6], $columns[7]\n";
}
}
I would like to get some guidance from experts so that I can enhance my understanding of Perl while working on the code.
Appreciate any help.
Regards
Perhaps the following will assist you:
use strict;
use warnings;
use Math::Complex;
my $dataFile = 'malto.dat';
{
local $/ = 'title ';
open my $fh, '<', $dataFile or die $!;
while (<$fh>) {
chomp;
my #data = split or next;
my $titleNum = 'Title ' . shift #data;
my $atom = shift(#data) . ' ' . shift #data;
my $resultantVel = calcResultantVel( \#data );
print $titleNum, "\n";
print $atom, "\n";
print 'ResultantVel: ' . $resultantVel, "\n\n";
}
close $fh;
}
sub calcResultantVel {
my ($dataRef) = #_;
my ($velocity_x, $velocity_y, $velocity_z);
while ( my #nums = splice( #$dataRef, 0, 9 ) ) {
$velocity_x += $nums[0] + $nums[3] + $nums[6];
$velocity_y += $nums[1] + $nums[4] + $nums[7];
$velocity_z += $nums[2] + $nums[5] + $nums[8];
}
return sqrt( $velocity_x**2 + $velocity_y**2 + $velocity_z**2 );
}
The word and space title is used as the record separator, so each read takes in a chunk of data that's delimited by title. The chomp removes the record separator, and then the record is split on whitespace.
The zeroth element is the title number, and that's shifted off #data. The first and second elements of #data are the atom count, and they're shifted off, too. The remaining array elements are the Cartesian directions, and a reference to that array is send to the subroutine calcResultantVel.
The subroutine takes a chunk of nine elements at a time: three for O atom, three for the first H atom, and three for the second H atom, and a running sum is kept based upon the definition you've provided. Finally, the resultant velocity is returned.
Here's some sample output:
Title 0
4335 2.0001000e+04
ResultantVel: 13.2945751170603
Title 1
4335 2.0001000e+04
ResultantVel: 12.7696611061461
You can visually verify that it's working correctly. Since you "...can write simple 'read and write' operations in Perl...," the next step is to have it write the desired results to a file.
Hope this helps!
Here's my advice: break the job down into small components, and write a method for each meaningful part of the work. To wit:
use strict;
use warnings;
main(#ARGV); # Pass data file name on command line. Don't hard-code it.
sub main {
my $data_f = shift;
open(my $data_h, '<', $data_f) or die "$!: $data_f";
while (my $section = get_section($data_h)){
# Also write methods that can be called here to make
# desired computations, print output, etc.
}
}
sub get_section {
# Takes a file handle.
# Returns a hash reference containing all of the data
# for an entire section of the file.
my $h = shift;
return if eof($h);
chomp (my $title = <$h>);
my ($n_atoms) = <$h> =~ /^(\d+)/;
return {
'title' => $title,
'n_atoms' => $n_atoms,
'molecules' => get_molecules($h, $n_atoms / 3),
};
}
sub get_molecules {
my #molecules;
return \#molecules;
}
I have not written the get_molecules() method. It takes a file handle and an integer (N of molecules). It could return a reference to an array-of-arrays or maybe an array-of-hashes, with each inner array/hash holding the info for a single molecule.
Thanks for your help and guide. I have tried to modify your code as below. It works at least for my need.
#!/usr/bin/perl
###############
#use strict;
#use warnings;
use Math::Complex;
open OUTPUT, '>', "velocityOnly.dat" or die "Can't create filehandle: $!";
my $dataFile = 'velF1F2.vel';
{
local $/ = 'title ';
open my $FH, '<', $dataFile or die $!;
while (<$FH>) {
chomp;
my #data = split or next;
my $titleNum = 'Title ' . shift(#data);
my $atom = shift(#data) . ' ' . shift(#data);
#my $resultantVel = calcResultantVel( \#data );
#print OUTPUT "$titleNum", "\n";
print "$titleNum", "\n";
for my $i (1..1445)
{
$j=(9*($i-1));
$velocity_x = $data[($j+0)] + $data[($j+3)] + $data[($j+6)];
$velocity_y = $data[($j+1)] + $data[($j+4)] + $data[($j+7)];
$velocity_z = $data[($j+2)] + $data[($j+5)] + $data[($j+8)];
$velo = sprintf '%.3f',sqrt( $velocity_x**2 + $velocity_y**2 + $velocity_z**2 );
chomp $velo;
print "$velo","\n";
print OUTPUT "$velo\n";
}
#print 'ResultantVel: ' . $resultantVel, "\n\n";
}
close $FH;
}
But I would like to extend further by adding some other functionality for doing some complex calculations. The code
Before that, I need some guide on making the below code into subroutine. I am bit lost here. Your CODE actually add all the X, Y and Z and finally find the velocity. But what I want is not that. Each 9 values subsequently represent coordinate for a water molecule which contain three atoms.
(The number 1445 is number of molecules. Each molecule contain three atoms and each atom has three coordinates.So for a water molecule has 9 Cartesian coordinates.)
the i here represent number of water molecule
for my $i (1..1445)
{
$j=(9*($i-1));
$velocity_x = $data[($j+0)] + $data[($j+3)] + $data[($j+6)];
$velocity_y = $data[($j+1)] + $data[($j+4)] + $data[($j+7)];
$velocity_z = $data[($j+2)] + $data[($j+5)] + $data[($j+8)];
$velo = sprintf '%.3f',sqrt( $velocity_x**2 + $velocity_y**2 + $velocity_z**2 );
chomp $velo;
print "$velo","\n";
print OUTPUT "$velo\n";
}

In Perl, how can I release memory to the operating system?

I am having some problems with memory in Perl. When I fill up a big hash, I can not get the memory to be released back to the OS. When I do the same with a scalar and use undef, it will give the memory back to the OS.
Here is a test program I wrote.
#!/usr/bin/perl
###### Memory test
######
## Use Commands
use Number::Bytes::Human qw(format_bytes);
use Data::Dumper;
use Devel::Size qw(size total_size);
## Create Varable
my $share_var;
my %share_hash;
my $type_hash = 1;
my $type_scalar = 1;
## Start Main Loop
while (true) {
&Memory_Check();
print "Hit Enter (add to memory): "; <>;
&Up_Mem(100_000);
&Memory_Check();
print "Hit Enter (Set Varable to nothing): "; <>;
$share_var = "";
$share_hash = ();
&Memory_Check();
print "Hit Enter (clean data): "; <>;
&Clean_Data();
&Memory_Check();
print "Hit Enter (start over): "; <>;
}
exit;
#### Up Memory
sub Up_Mem {
my $total_loops = shift;
my $n = 1;
print "Adding data to shared varable $total_loops times\n";
until ($n > $total_loops) {
if ($type_hash) {
$share_hash{$n} = 'X' x 1111;
}
if ($type_scalar) {
$share_var .= 'X' x 1111;
}
$n += 1;
}
print "Done Adding Data\n";
}
#### Clean up Data
sub Clean_Data {
print "Clean Up Data\n";
if ($type_hash) {
## Method to fix hash (Trying Everything i can think of!
my $n = 1;
my $total_loops = 100_000;
until ($n > $total_loops) {
undef $share_hash{$n};
$n += 1;
}
%share_hash = ();
$share_hash = ();
undef $share_hash;
undef %share_hash;
}
if ($type_scalar) {
undef $share_var;
}
}
#### Check Memory Usage
sub Memory_Check {
## Get current memory from shell
my #mem = `ps aux | grep \"$$\"`;
my($results) = grep !/grep/, #mem;
## Parse Data from Shell
chomp $results;
$results =~ s/^\w*\s*\d*\s*\d*\.\d*\s*\d*\.\d*\s*//g; $results =~ s/pts.*//g;
my ($vsz,$rss) = split(/\s+/,$results);
## Format Numbers to Human Readable
my $h = Number::Bytes::Human->new();
my $virt = $h->format($vsz);
my $h = Number::Bytes::Human->new();
my $res = $h->format($rss);
print "Current Memory Usage: Virt: $virt RES: $res\n";
if ($type_hash) {
my $total_size = total_size(\%share_hash);
my #arr_c = keys %share_hash;
print "Length of Hash: " . ($#arr_c + 1) . " Hash Mem Total Size: $total_size\n";
}
if ($type_scalar) {
my $total_size = total_size($share_var);
print "Length of Scalar: " . length($share_var) . " Scalar Mem Total Size: $total_size\n";
}
}
OUTPUT:
./Memory_Undef_Simple.cgi
Current Memory Usage: Virt: 6.9K RES: 2.7K
Length of Hash: 0 Hash Mem Total Size: 92
Length of Scalar: 0 Scalar Mem Total Size: 12
Hit Enter (add to memory):
Adding data to shared varable 100000 times
Done Adding Data
Current Memory Usage: Virt: 228K RES: 224K
Length of Hash: 100000 Hash Mem Total Size: 116813243
Length of Scalar: 111100000 Scalar Mem Total Size: 111100028
Hit Enter (Set Varable to nothing):
Current Memory Usage: Virt: 228K RES: 224K
Length of Hash: 100000 Hash Mem Total Size: 116813243
Length of Scalar: 0 Scalar Mem Total Size: 111100028
Hit Enter (clean data):
Clean Up Data
Current Memory Usage: Virt: 139K RES: 135K
Length of Hash: 0 Hash Mem Total Size: 92
Length of Scalar: 0 Scalar Mem Total Size: 24
Hit Enter (start over):
So as you can see the memory goes down, but it only goes down the size of the scalar. Any ideas how to free the memory of the hash?
Also Devel::Size shows the hash is only taking up 92 bytes even though the program still is using 139K.
Generally, yeah, that's how memory management on UNIX works. If you are using Linux with a recent glibc, and are using that malloc, you can return free'd memory to the OS. I am not sure Perl does this, though.
If you want to work with large datasets, don't load the whole thing into memory, use something like BerkeleyDB:
https://metacpan.org/pod/BerkeleyDB
Example code, stolen verbatim:
use strict ;
use BerkeleyDB ;
my $filename = "fruit" ;
unlink $filename ;
tie my %h, "BerkeleyDB::Hash",
-Filename => $filename,
-Flags => DB_CREATE
or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ;
# Add a few key/value pairs to the file
$h{apple} = "red" ;
$h{orange} = "orange" ;
$h{banana} = "yellow" ;
$h{tomato} = "red" ;
# Check for existence of a key
print "Banana Exists\n\n" if $h{banana} ;
# Delete a key/value pair.
delete $h{apple} ;
# print the contents of the file
while (my ($k, $v) = each %h)
{ print "$k -> $v\n" }
untie %h ;
(OK, not verbatim. Their use of use vars is ... legacy ...)
You can store gigabytes of data in a hash this way, and you will only use a tiny bit of memory. (Basically, whatever BDB's pager decides to keep in memory; this is controllable.)
In general, you cannot expect perl to release memory to the OS.
See the FAQ: How can I free an array or hash so my program shrinks?.
You usually can't. Memory allocated to lexicals (i.e. my() variables) cannot be reclaimed or reused even if they go out of scope. It is reserved in case the variables come back into scope. Memory allocated to global variables can be reused (within your program) by using undef() and/or delete().
On most operating systems, memory allocated to a program can never be returned to the system. That's why long-running programs sometimes re- exec themselves. Some operating systems (notably, systems that use mmap(2) for allocating large chunks of memory) can reclaim memory that is no longer used, but on such systems, perl must be configured and compiled to use the OS's malloc, not perl's.
It is always a good idea to read the FAQ list, also installed on your computer, before wasting your time.
For example, How can I make my Perl program take less memory? is probably relevant to your issue.
Why do you want Perl to release the memory to the OS? You could just use a larger swap.
If you really must, do your work in a forked process, then exit.
Try recompiling perl with the option -Uusemymalloc to use the system malloc and free. You might see some different results