• Hey, guest user. Hope you're enjoying NeoGAF! Have you considered registering for an account? Come join us and add your take to the daily discourse.

Programming |OT| C is better than C++! No, C++ is better than C

Are you having trouble with how to create and manage threads with pthreads, like trouble with just using pthreads at all? or is it more how to do matrix multiplication in parallel?

The former, hence why I'm looking for any tutorials or examples people here can link/show me. I've worked with matrices before but was around 2 years ago, so might need help in that regard too, regardless PThreads first.

Edit: Honestly I'm more trying to figure out what the description in the .pdf want me to do and what steps I should pre-plan out.
 
The former, hence why I'm looking for any tutorials or examples people here can link/show me. I've worked with matrices before but was around 2 years ago, so might need help in that regard too, regardless PThreads first.

Edit: Honestly I'm more trying to figure out what the description in the .pdf want me to do and what steps I should pre-plan out.

It doesn't say pthreads AFAICT, and it also says you can use C++. C++ threads are drastically simpler to use, you can get a thread up and running in 5 lines of code. Google for "std thread" and look for the cppreference link
 

Massa

Member
The former, hence why I'm looking for any tutorials or examples people here can link/show me. I've worked with matrices before but was around 2 years ago, so might need help in that regard too, regardless PThreads first.

Edit: Honestly I'm more trying to figure out what the description in the .pdf want me to do and what steps I should pre-plan out.

I'm sure you've seen it by now but the first Google result is pretty good: https://computing.llnl.gov/tutorials/pthreads/

If you're looking for a bit of an easier way to deal with threads, in addition to what cpp_is_king has said, I'd recommend checking out OpenMP (which you can use with C and other languages).
 

Koren

Member
Btw, one of your original points about the lookup table
You're right, of course... Both on the cache misses and on the idea of the table to speed the process. If you have several conversions to do, it's definitively the way to go if you go for speed, and it's a nice one. I can only blame the lack of sleep yesterday ^_^

Does this seem right thus far for the first part?

About:
Code:
	lb $t6, 0 ($s3) #$s3 is Set1
[...]
	addiu $s3, $s3, 1

As far as I understand, it's not a table of bytes, it's a 32-bits values that handle 32 bits as flags. So there's no reason to load each bit separatedly (and it won't work). I would simply put in the "preamble"
Code:
li $t6, 0xaaaaaaaa
if you want to load the set as an immediate value, or
Code:
lw $t6, 0 ($s3) #$s3 is Set1
if the 32-bits value is stored in memory (as a single, 32-bits word)

Then, there's a lack of actual test for the bit, if I'm not mistaken. If you want to use a shifted bit to check the bit, you can use
Code:
ssl $t7, $t7, 1

The actual test for the bit is
Code:
and $t3, $t6, $t7
then do the printing ONLY if the result is non-zero (you probably want to compare the result to 0 with a beq comparison). It seems that you never test the bit before printing?

Then, if I'm not mistaken, because of
Code:
li $t4, 0
it will print 0 for first set, and the assignment says that the first set is 1?


I'd say, for example~:
Code:
       li $t3, 0x0       # A zero to test the results
       li $t4, 0x1       # Number of the first set
       lw $t6, ($s3)     # Load set from address $s3
       li $t7, 0x1       # Shifted bit for test

loop : and $t5, $t6, $t7     # Test the bit
       beq $t5, $t3, zero    # Result is non-zero only if the bit is set

       li $v0, 1         # system call code for integer print
       move $a0, $t4	 # set integer to be printed
       syscall	         # print the integer

zero : bltz $t7, end      # A trick: if $t7 contains 0x80000000, it's finished
       sll $t7, $t7, 1    # shift the bit one place left
       addi $t4, $t4, 1   # add 1 to the set number
       b loop

end :
I hope it's correct, I haven't written MIPS assembly in ages... I don't even remember which registers you're entitled to use, so you should check this ($t3 is OK?), and also the correctness of the branching instructions.

There's a trick in the code. Since there's 32 bits, and values in register are 32 bits, instead of testing $t7 = 0x80000000 (the bit is in the left most place), I test the *sign* of $t7$. Since it's 2C values, bltz actually test the left most bit, and jump if it's 1. You avoid wasting a comparison, spare a couple registers and cycles.

Or (my first idea, but a bit different from the suggestion)
Code:
       li $t2, 0x0       # A one to test the results
       li $t3, 0x0       # A zero to test the results
       li $t4, 0x1       # The number of the set
       lw $t6, ($s3)     # Load set from address $s3
       li $t7, 0x32      # Max number of sets

loop : and $t5, $t6, $t2     # Test the lowest bit
       beq $t5, $t3, zero    # Result is non-zero only if the bit is set

       li $v0, 1         # system call code for integer print
       move $a0, $t4	 # set integer to be printed
       syscall	         # print the integer

zero : beq $t7, $t4, end  # check whether it was the last set
       srl $t6, $t6, 1    # shift the bit one place right to test next bit
       addi $t4, $t4, 1   # add 1 to the set number
       b loop

end :
Again, check whether you can use $t2 and $t3, I don't remember...

I thought my first idea was better, but with the lack of branch-if-zero and branch-if-non-zero, if I read correctly the instruction set (I've done far more i86 and similar ASM), you need more registers to store a 0 and a 1...
 

Koren

Member
The second assignment is actually simpler (no loop)

Code:
       lw $t6, ($s3)      # Load set from address $s3

       li $t4, 0x17       # The number of the wanted set (start at 1)
       
       addi $t5, $t4, -1  # Remove 1
       srlv $t6, $t6, $t5 # Shift the word so that the interesting bit is the lowest one

       li $t5, 0x01        # bit for thesting
       and $t5, $t5, $t6   # keep only the lowest bit
       blez end            # not in set, do nothing

       li $v0, 1         # system call code for integer print
       move $a0, $t4	 # set integer to be printed
       syscall	         # print the integer

end :

the last two ones are trivial (bitwise OR and bitwise AND)
 

Erudite

Member
Maybe GAF can help me understand what's going on the in call stack a little better?

So here's the code:
Code:
/* A program to demonstrate printing out partial contents of the call stack */
#include <iostream>
#include <iomanip>
using namespace std;

int print_stack(int k, int j){
   cout << "print_stack() begins" << endl;

   cout << "argument k is at &k=" << &k << "  and k=" << k << endl;
   cout << "argument j is at &j=" << &j << "  and j=" << j << endl;

   int CCC[2] = { 77777777, 88888888 } ;

   cout << "Peeking from &j up, for the space of k ints" << endl ;
   int *p = (&j)+k ;
   for( int l = k ; l > 0 ; l-- ){
       cout << p << ": " <<  setw(8) << hex << *p << " =  " << setw(11) << dec << *p << endl ;
       p -= j ;// subtractin j from an int pointer sets it to the j-th previous int
   }
   cout << "End of: print_stack()" << endl;
}

int ffff(int fun_arg){
    cout << "fun() begins" << endl;

    cout << "fun_arg is at &fun_arg=" << &fun_arg << endl;

    int BBB[2] = { 444444444, 555555555 } ;
    cout << "BBB is at BBB=" << BBB << endl;

    print_stack(40,+1);

    cout << "fun ends" << endl;
}

int main(){
    cout << "main() begins\n";

    int XXXX = 999999999 ;

    int AAAA[2] = { 111111111, 222222222 } ;//  

    ffff( 333333333 );

    cout << "main() ends" << endl ;
}
And the output:
Code:
main() begins
fun() begins
fun_arg is at &fun_arg=0x7ffff3ef9ecc
BBB is at BBB=0x7ffff3ef9ed0
print_stack() begins
argument k is at &k=0x7ffff3ef9e6c  and k=40
argument j is at &j=0x7ffff3ef9e68  and j=1
Peeking from &j up, for the space of k ints
0x7ffff3ef9f08: 5c21d9c4 =   1545722308
0x7ffff3ef9f04:        0 =            0
0x7ffff3ef9f00:        0 =            0
0x7ffff3ef9efc: 3b9ac9ff =    999999999
0x7ffff3ef9ef8:        0 =            0
0x7ffff3ef9ef4:  d3ed78e =    222222222
0x7ffff3ef9ef0:  69f6bc7 =    111111111
0x7ffff3ef9eec:        0 =            0
0x7ffff3ef9ee8:   400c92 =      4197522
0x7ffff3ef9ee4:     7fff =        32767
0x7ffff3ef9ee0: f3ef9f00 =   -202400000
0x7ffff3ef9edc:        0 =            0
0x7ffff3ef9ed8:        0 =            0
0x7ffff3ef9ed4: 211d1ae3 =    555555555
0x7ffff3ef9ed0: 1a7daf1c =    444444444
0x7ffff3ef9ecc: 13de4355 =    333333333
0x7ffff3ef9ec8: f3ef9fe0 =   -202399776
0x7ffff3ef9ec4:        0 =            0
0x7ffff3ef9ec0:        0 =            0
0x7ffff3ef9ebc:        0 =            0
0x7ffff3ef9eb8:   400c3e =      4197438
0x7ffff3ef9eb4:     7fff =        32767
0x7ffff3ef9eb0: f3ef9ee0 =   -202400032
0x7ffff3ef9eac:        0 =            0
0x7ffff3ef9ea8:        0 =            0
0x7ffff3ef9ea4:     7fff =        32767
0x7ffff3ef9ea0: f3ef9fe0 =   -202399776
0x7ffff3ef9e9c:        0 =            0
0x7ffff3ef9e98:        0 =            0
0x7ffff3ef9e94:       30 =           48
0x7ffff3ef9e90: 5c01cbc0 =   1543621568
0x7ffff3ef9e8c:        9 =            9
0x7ffff3ef9e88: 5c260440 =   1545995328
0x7ffff3ef9e84:     7fff =        32767
0x7ffff3ef9e80: f3ef9e80 =   -202400128
0x7ffff3ef9e7c:       30 =           48
0x7ffff3ef9e78: 5c26b397 =   1546040215
0x7ffff3ef9e74:  54c5638 =     88888888
0x7ffff3ef9e70:  4a2cb71 =     77777777
0x7ffff3ef9e6c:       28 =           40
End of: print_stack()
fun ends
main() ends

So when I initially looked at the code before I executing it, I figured the variables would be stored in memory in the order that the functions were called (eg. main() -> ffff() -> print_stack() ).

Looking at the code and at my notes however, it seems everything is being stored backwards in memory? So the contents of print_stack() get stored first, then ffff(), then main(). Am I understanding that correctly? If so, is there some advantage to storing local variables like this, or just a subtlety of C++ I should know?

Any help would be much appreciated.
 
It doesn't say pthreads AFAICT, and it also says you can use C++. C++ threads are drastically simpler to use, you can get a thread up and running in 5 lines of code. Google for "std thread" and look for the cppreference link

I'm sure you've seen it by now but the first Google result is pretty good: https://computing.llnl.gov/tutorials/pthreads/

If you're looking for a bit of an easier way to deal with threads, in addition to what cpp_is_king has said, I'd recommend checking out OpenMP (which you can use with C and other languages).

Getting a hand of multithreading (C++ speicifically), now the next part is matrix multiplication with it, which I'm drawing blanks on.
 

Kalentan

Member

Hey, I think my code earlier might be causing this to not work?

Code:
la $t0, printSet
	
	li	$v0, 4		#System call code for Print
	la	$a0, Prompt	#load add.dress of prompt into $a0
	syscall	
	li	$v0, 8
	la	$a0, Set1
	la	$a1, 80
	syscall			#print the prompt message
	
	li	$v0, 4		#System call code for Print
	la	$a0, Prompt2	#load add.dress of prompt into $a0
	syscall	
	li	$v0, 8
	la	$a0, Set2
	la	$a1, 80
	syscall			#print the prompt message
	
	la $s0, Set1
	la $s1, Set2
	
	move $s3, $s0
	jalr $s6, $t0
	
	move $s3, $s1
	jalr $s6, $t0

It's not crashing, nor giving Exception errors, but it doesn't print out the sets.

I think it's getting to here:

Code:
beq $t5, $t3, check    # Result is non-zero only if the bit is set

Then it jumps to here:
Code:
beq $t7, $t4, back  # check whether it was the last set

So it never actually does anything. Because 2 these are satisfied, so it goes to 'back' and then goes back...
 

Koren

Member
So when I initially looked at the code before I executing it, I figured the variables would be stored in memory in the order that the functions were called (eg. main() -> ffff() -> print_stack() ).

Looking at the code and at my notes however, it seems everything is being stored backwards in memory? So the contents of print_stack() get stored first, then ffff(), then main(). Am I understanding that correctly? If so, is there some advantage to storing local variables like this, or just a subtlety of C++ I should know?

Any help would be much appreciated.
I find a couple things strange (but that's probably just because I haven't looked carefully), but the idea is that the stack is filling up from high adresses to lower ones (while heap go the other way).

Start :

high
---------- TOP OF STACK


free RAM


----------
(heap)
----------
bottom


Main :


high
----------
main local variables
---------- TOP OF STACK

free RAM

----------
(heap)
----------
bottom


First function :

high
----------
main local variables
----------
return adress and arguments
local variables of the function
---------- TOP OF STACK

free RAM

----------
(heap)
----------
bottom

etc.

Not sure about the definitive reasons for the "backwards filling", but I can see some possibilities :
- with heap (the memory you'll usually get when you reserve a chunk with a malloc) going up, it's easier if the stack (the memory used for function calls, arguments and local variables) is filling the ram from the other side
- with stack filling the ram from top to bottom, the local variables have an address that is top-of-the-stack + positive offset, which is slightly easier, I guess.


It's not a "C" way to do this, all languages translated in assembly will use the same memory management (well, sort of... and in fact, the stack can sometimes go both ways). It's needed so that you can combine parts of programs written in different languages (although there's plently of strategies for where the arguments and return value should go, sot it's often a mess).
 

Koren

Member
Hey, I think my code earlier might be causing this to not work?
Would you mind posting or pastebin-ing the whole program?

Because I can't figure what you mean... I see the two last lines, with the branch-if-equal, nowhere, so I have no idea where they jump and what registers contains... so it's a bit hard to reply ^_^
 

Koren

Member
Maybe GAF can help me understand what's going on the in call stack a little better?
Besides what I was saying earlier, care to specify:
- the OS
- the compiler
- the compiling options (-g, -o, etc. if gcc)
- 32 or 64 bits
?

Because things change a bit depending on those. I've got plently of different stacks when trying on my own computer, but beside the order in which the local variables and return address are stored, there's not a lot in common.

I fact, I'm surprised because it seems that local variables are stored on the stack apparently before the parameters. But I'm not sure that the 33333333 and 40 are actually parameters. Back in x86 days, parameters were often passed on the stack, but now they're usually passed on registers, especially on 64bits machines.


But your code is awfully tricky! And using cout to check the stack is not the best idea.

I suspect that j and k are passed in registers, but the &j you use force the compiler to copy the register into the stack, like a local variable, so that you can get an address (since registers can't offer you an address). Simply by checking the address, you *change* the behavior of the calls, and how the compiler handle this is not obvious. AT ALL.


Edit: Yes, I'm more and more sure it's that...

When you call ffff :
- arguments are put in registers
- local variables are put in the stack, alongside the return address

at this time, fun_arg is NOT in the stack.

But since the compiler find &fun_arg, it understand you want it to be in memory, not in register, so it copy the value from the register to the stack, as if you had declared a local variable... thus it appears *after* the local variable, which may seems strange. But in fact, it's not.

You could think that it's strange that the compiler put the argument in a register, then copy it into the stack, and could have put it directly into the stack instead. But the problem is that the compiler that compile ffff() and the other function *knows* he'll need them in stack, but the compiler that compile main don't know anything about the code inside ffff(), so the conventions for where parameters go HAVE to be followed to the letter, even if that means an additionnal copy in ffff().


There's a couple of strange values in the stack, but I wouldn't be surprised that some of them are simply there because of qword alignment optimization.

Can someone confirm I'm right here?


(Btw, I think having a grasp at the way stack, heap, function calls & co works helps a bit the programmer to understand how the computer work, if only to understand the tail-elimination in recursive calls, but I'm not sure looking at stacks produced by an actual compiler is the best idea to understand how things work... it's one of the situation where doing some assembly is nice, you can always try to call a C function from assembly)
 

Erudite

Member
Besides what I was saying earlier, care to specify:
- the OS
- the compiler
- the compiling options (-g, -o, etc. if gcc)
- 32 or 64 bits
?
The only information I have on hand is that my school's terminal uses Ubuntu 14.04, as I grabbed the output yesterday and copied it to a text file to study this morning, using plain old 'g++ stack.cpp'. If I were to guess, it's running 64-bit.

I appreciate thorough response. The code was just provided as a means to study for a quiz coming up. I imagine the question will go something along the lines of having several functions calling one another (eg. A() calls B() calls C() ) and needing to roughly show what order the variables will be stored, so knowing that the variables are stored in the call stack from high addresses to low addresses will help a lot.
 

Koren

Member

Many thanks, far easier this way... ^_^

I think it's getting to here:

Code:
beq $t5, $t3, check    # Result is non-zero only if the bit is set

Then it jumps to here:
Code:
beq $t7, $t4, back  # check whether it was the last set

So it never actually does anything. Because 2 these are satisfied, so it goes to 'back' and then goes back...
Have you tried with a 0xFFFFFFFF set to avoid the first jump?

In any case, t4 and t7 contains 1 and 32 at the first iteration, so it should shift, add, and go back to loop in any case.

How do you test it? On an actual MIPS, or do you have a kind of emulator I could install myself? I don't see any obvious flaw :/


Could you add a couple of lines, directly after the loop: (before any and / comparison) that print the content of t4?

I don't have any memory of printing in assembly on MIPS, but could it be a flushing issue? Does the program return? Do you get all the other messages, especially Result2 and Bye?
 

Koren

Member
The only information I have on hand is that my school's terminal uses Ubuntu 14.04, as I grabbed the output yesterday and copied it to a text file to study this morning, using plain old 'g++ stack.cpp'. If I were to guess, it's running 64-bit.
Probably...

I'd use -O0 (no optimization) to avoid some tricks the compiler could do...

I was looking for some images on the net to clarify things, had limited success, for example with this page : http://dralu.com/?cat=3&paged=3
(just for the images, I haven't read the content)


The RAM is ordered like this:
virtual_address_layout-192x300.gif

Stack on top, filling downwards, heap on bottop, filling upwards.

Consider this program:
Code:
int a() {
   b();
   c();
   return 0;
}

int b() {
   return 0;
}

int c() {
   return 0;
}

int main() {
  a();
  return 0;
}

Successive calls gives this:
stack_sample_layout_2.png


Each "frame" for each call contains something like this:
stack_layout.png


except parameters are NOT in the stack anymore, and if you find them in the stack, I'm convinced now that it's because of the &j and the result of a copy (indeed, my compiler copy them from registers to the stack as local variables because of &j and co)

I appreciate thorough response.
You're welcome... I hope I could help, and best wishes for the test...
 

Kalentan

Member
Many thanks, far easier this way... ^_^


Have you tried with a 0xFFFFFFFF set to avoid the first jump?

In any case, t4 and t7 contains 1 and 32 at the first iteration, so it should shift, add, and go back to loop in any case.

How do you test it? On an actual MIPS, or do you have a kind of emulator I could install myself? I don't see any obvious flaw :/


Could you add a couple of lines, directly after the loop: (before any and / comparison) that print the content of t4?

I don't have any memory of printing in assembly on MIPS, but could it be a flushing issue? Does the program return? Do you get all the other messages, especially Result2 and Bye?

0xFFFFFFFF didn't skip it. Also question, do I actually type in 0xFFFFFFFF? Or FFFFFFFF and it's a string right?

Also I'm testing this in PCSpim.

Should be noted that when I move Set1 and Set2 to s0 and s1, the registers say they're.... 10010014 and 10010064.

Also when I added the print after the loop it printed '50'.

Result2 and Bye do print.
 

Koren

Member
0xFFFFFFFF didn't skip it. Also question, do I actually type in 0xFFFFFFFF? Or FFFFFFFF and it's a string right?

Also I'm testing this in PCSpim.

Should be noted that when I move Set1 and Set2 to s0 and s1, the registers say they're.... 10010014 and 10010064.

Also when I added the print after the loop it printed '50'.

Result2 and Bye do print.
OK, found the bug after installing QtSpim.

A stupid one...

Code:
 li $t2, 0x0       # A one to test the results
A *one*. So, it's
Code:
 li $t2, 0x1       # A one to test the results
obvioulsy!

Sorry.


Also, it's 0x20 and not 0x32 for 32-bits sets... (this is the reason you get 50 instead of 32, since 0x32 = 50)

Now, it prints something. Not sure what, though (how do you enter the sets when prompted for it?), but it seems to work well.


Edit: yes, the print function works now when I put values directly in $t6, and prints the correct list of sets. Sorry for the 0x0 :/
 

Koren

Member
And about the input, I've just checked, you read a string... so you have first to convert into a word before doing anything with it (print it, test for a given element, and, or...)

You need another function...

I'd suggest this: enter the string as a string of 0, 1. Then parse the string to the final NULL value, left shift each time you have a 0, left shift and OR 0x1 each time you have a 1.

Assuming $s6 contains the address of the string, the following read the string in ASCII from ($s6) till the NULL char signalling the end and build the bit string in $t7.

Warning : if you enter less than 32 zeros and ones, it'll fill with zeros on the left. If you enter more than 32 zeros and ones, it'll drop the first ones in excess.

Code:
       li $t7, 0x0     # Will contain the bit string
       li $t6, 0x30    # ASCII value for '0'
       li $t5, 0x31    # ASCII value for '1'
       li $t4, 0x0     # End-of-string character
 
loop : lb $t3, ($s6)
       beq $t3, $t4, endstring
       beq $t3, $t5, one
       beq $t3, $t6, zero

       b next

one :  sll $t7, $t7, 1
       ori $t7, $t7, 0x1
       b next

zero : sll $t7, $t7, 1

next : addi $s6, $s6, 1
       b loop

endstring :

The result, which is a single word, should land in $t6 at the beginning of the PrintSet...
 
Getting a hand of multithreading (C++ speicifically), now the next part is matrix multiplication with it, which I'm drawing blanks on.

Make 1 thread for each coordinate of the result matrix. When you create the std::thread, pass it the coordinate that that thread will work on, as well as the 2 input matrices and the output matrix.

All you need then is 1 thread function that takes 4 inputs. 2 input matrices, an output matrix, and an output coordinate. The body of that function is basically one iteration of the outer loop when you do the single threaded multiplication
 
Maybe GAF can help me understand what's going on the in call stack a little better?

So here's the code:
Code:
/* A program to demonstrate printing out partial contents of the call stack */
#include <iostream>
#include <iomanip>
using namespace std;

int print_stack(int k, int j){
   cout << "print_stack() begins" << endl;

   cout << "argument k is at &k=" << &k << "  and k=" << k << endl;
   cout << "argument j is at &j=" << &j << "  and j=" << j << endl;

   int CCC[2] = { 77777777, 88888888 } ;

   cout << "Peeking from &j up, for the space of k ints" << endl ;
   int *p = (&j)+k ;
   for( int l = k ; l > 0 ; l-- ){
       cout << p << ": " <<  setw(8) << hex << *p << " =  " << setw(11) << dec << *p << endl ;
       p -= j ;// subtractin j from an int pointer sets it to the j-th previous int
   }
   cout << "End of: print_stack()" << endl;
}

int ffff(int fun_arg){
    cout << "fun() begins" << endl;

    cout << "fun_arg is at &fun_arg=" << &fun_arg << endl;

    int BBB[2] = { 444444444, 555555555 } ;
    cout << "BBB is at BBB=" << BBB << endl;

    print_stack(40,+1);

    cout << "fun ends" << endl;
}

int main(){
    cout << "main() beginsn";

    int XXXX = 999999999 ;

    int AAAA[2] = { 111111111, 222222222 } ;//  

    ffff( 333333333 );

    cout << "main() ends" << endl ;
}
And the output:
Code:
main() begins
fun() begins
fun_arg is at &fun_arg=0x7ffff3ef9ecc
BBB is at BBB=0x7ffff3ef9ed0
print_stack() begins
argument k is at &k=0x7ffff3ef9e6c  and k=40
argument j is at &j=0x7ffff3ef9e68  and j=1
Peeking from &j up, for the space of k ints
0x7ffff3ef9f08: 5c21d9c4 =   1545722308
0x7ffff3ef9f04:        0 =            0
0x7ffff3ef9f00:        0 =            0
0x7ffff3ef9efc: 3b9ac9ff =    999999999
0x7ffff3ef9ef8:        0 =            0
0x7ffff3ef9ef4:  d3ed78e =    222222222
0x7ffff3ef9ef0:  69f6bc7 =    111111111
0x7ffff3ef9eec:        0 =            0
0x7ffff3ef9ee8:   400c92 =      4197522
0x7ffff3ef9ee4:     7fff =        32767
0x7ffff3ef9ee0: f3ef9f00 =   -202400000
0x7ffff3ef9edc:        0 =            0
0x7ffff3ef9ed8:        0 =            0
0x7ffff3ef9ed4: 211d1ae3 =    555555555
0x7ffff3ef9ed0: 1a7daf1c =    444444444
0x7ffff3ef9ecc: 13de4355 =    333333333
0x7ffff3ef9ec8: f3ef9fe0 =   -202399776
0x7ffff3ef9ec4:        0 =            0
0x7ffff3ef9ec0:        0 =            0
0x7ffff3ef9ebc:        0 =            0
0x7ffff3ef9eb8:   400c3e =      4197438
0x7ffff3ef9eb4:     7fff =        32767
0x7ffff3ef9eb0: f3ef9ee0 =   -202400032
0x7ffff3ef9eac:        0 =            0
0x7ffff3ef9ea8:        0 =            0
0x7ffff3ef9ea4:     7fff =        32767
0x7ffff3ef9ea0: f3ef9fe0 =   -202399776
0x7ffff3ef9e9c:        0 =            0
0x7ffff3ef9e98:        0 =            0
0x7ffff3ef9e94:       30 =           48
0x7ffff3ef9e90: 5c01cbc0 =   1543621568
0x7ffff3ef9e8c:        9 =            9
0x7ffff3ef9e88: 5c260440 =   1545995328
0x7ffff3ef9e84:     7fff =        32767
0x7ffff3ef9e80: f3ef9e80 =   -202400128
0x7ffff3ef9e7c:       30 =           48
0x7ffff3ef9e78: 5c26b397 =   1546040215
0x7ffff3ef9e74:  54c5638 =     88888888
0x7ffff3ef9e70:  4a2cb71 =     77777777
0x7ffff3ef9e6c:       28 =           40
End of: print_stack()
fun ends
main() ends

So when I initially looked at the code before I executing it, I figured the variables would be stored in memory in the order that the functions were called (eg. main() -> ffff() -> print_stack() ).

Looking at the code and at my notes however, it seems everything is being stored backwards in memory? So the contents of print_stack() get stored first, then ffff(), then main(). Am I understanding that correctly? If so, is there some advantage to storing local variables like this, or just a subtlety of C++ I should know?

Any help would be much appreciated.

This is not a property of c++ it's a property of x86 architecture. Stack grows downward. In other words, if you push something onto the stack, the new stack pointer is now less than the old stack pointer.

Btw, it's much easier to do this kind of exploration with a debugger. Get the value of esp or rsp, open a memory window to that address, and step through the assembly, you can see exactly how the stack changes as you step through the program
 

Koren

Member
Btw, it's much easier to do this kind of exploration with a debugger.
I agree. I'd be curious to see on which instruction the program move the arguments from a register to the stack because of the $j...

Also I'm testing this in PCSpim.
Done rewriting the whole program...

Code:
##############################################
# Program Name: Test read/write bit string
# Programmer: Koren
# Date: 10/14/2015
#############################################

.data   # Data declaration section

Prompt1: .asciiz "Set1: "
Prompt2: .asciiz "Set2: "
Buffer:  .space 80
Comma:   .asciiz ","
NewLine: .asciiz "\n"
Union:   .asciiz "Union of sets: "
Inters:  .asciiz "Intersection of sets: "
Result:  .asciiz "The set is: "
Bye:     .asciiz "Have a nice day."

.globl  main
.text
               
main:
        li $v0, 4            # System call code for Print
        la $a0, Prompt1      # Load adddress of prompt into $a0
        syscall
       
        la $t0, readSet      # Use readSet to read the set from standard input
        jalr $s6, $t0           
        move $s1, $s3        # Store a copy of the result in $s1
        
        li $v0, 4            # System call code for Print String
        la $a0, Result       # Load address of msg into $a0
        syscall              # Print the string
        
        la $t0, printSet     # Use printSet to print the first set
        jalr $s6, $t0
        
        li $v0, 4            # System call code for Print
        la $a0, Prompt2      # Load adddress of prompt into $a0
        syscall
       
        la $t0, readSet      # Use readSet to read the set from standard input
        jalr $s6, $t0           
        move $s2, $s3        # Store a copy of the result in $s2
        
        li $v0, 4            # System call code for Print String
        la $a0, Result       # Load address of msg into $a0
        syscall              # Print the string
        
        la $t0, printSet     # Use printSet to print the second set
        jalr $s6, $t0
        
        
        li $v0, 4            # System call code for Print String
        la $a0, Union        # Load address of msg into $a0
        syscall              # Print the string

        or $s3, $s1, $s2     # Compute the union
        
        la $t0, printSet     # Use printSet to print the union
        jalr $s6, $t0
        
        
        li $v0, 4            # System call code for Print String
        la $a0, Inters       # Load address of msg into $a0
        syscall              # Print the string
        
        and $s3, $s1, $s2    # Compute the intersection

        la $t0, printSet     # Use printSet to print the union
        jalr $s6, $t0
        
        li $v0, 4            # System call code for Print String
        la $a0, Bye          # Load address of msg into $a0
        syscall
        
        li $v0, 10           # Terminate program and
        syscall              # Return control to the system

##############################################################

readSet: # Read from standard input, the result will be in $s3, use $t3-$t7

        li $v0, 8
        la $a0, Buffer
        la $a1, 80
        syscall
        
        move $s3, $a0
        
        li $t7, 0x0     # Will contain the bit string
        li $t6, 0x30    # ASCII value for '0'
        li $t5, 0x31    # ASCII value for '1'
        li $t4, 0x0     # End-of-string character
 
rloop : lb $t3, ($s3)
        beq $t3, $t4, endread
        beq $t3, $t5, one
        beq $t3, $t6, zero

        b next

one :   sll $t7, $t7, 1
        ori $t7, $t7, 0x1
        b next

zero :  sll $t7, $t7, 1

next :  addi $s3, $s3, 1
        b rloop

endread : move $s3, $t7
        jr $s6

##############################################################

printSet: # Assume the set to print is a word in $s3, will modify $t2-$t7

        move $t6, $s3        # Move the set into $t6
        
        li $t2, 0x1          # A one to test the results
        li $t3, 0x0          # A zero to test the results
        li $t4, 0x1          # The number of the set
        li $t7, 0x20         # Max number of sets

loop:   and $t5, $t6, $t2    # Test the lowest bit                
        beq $t5, $t3, check  # Result is non-zero only if the bit is set

        li $v0, 1            # System call code for integer print
        move $a0, $t4        # Set integer to be printed
        syscall              # print the integer

        li $v0, 4            # System call code for Print String
        la $a0, Comma        # Load address of msg into $a0
        syscall              # Print the string
 
check:  beq $t7, $t4, back   # check whether it was the last set
        srl $t6, $t6, 1      # shift the bit one place right to test next bit
        addi $t4, $t4, 1     # add 1 to the set number
        b loop

back:   li $v0, 4            # System call code for Print String
        la $a0, NewLine      # Load address of msg into $a0
        syscall              # Print the string
        jr $s6
           
##############################################################

This is what I enter and what I get (read two sets, convert input to words, write their content, compute and display union and intersection):

Code:
Set1: 0010 0001 1001 1110 0110 0010 1001 0110
The set is: 2,3,5,8,10,14,15,18,19,20,21,24,25,30,
Set2: 0101 0010 0011 0011 0010 1101 0010 0010
The set is: 2,6,9,11,12,14,17,18,21,22,26,29,31,
Union of sets: 2,3,5,6,8,9,10,11,12,14,15,17,18,19,20,21,22,24,25,26,29,30,31,
Intersection of sets: 2,14,18,21,
Have a nice day.

Hope that helps...

Anything besides 0 and 1 are ignored on inputs, so you can remove spaces, add commas, etc.

There's still a comma that isn't nice in the output, but removing it make everything less readable.
 
I've been playing around with glium over the last couple of days and it's really, really cool. It's an OpenGL library for Rust that wraps the ugly beast that is the OpenGL state machine and exposes a nice Rust-idiomatic API. The coolest thing about is the following (quote from the Github page):
Glium detects what would normally be errors or undefined behaviors in OpenGL, and panics, without calling glGetError which would be too slow. Examples include requesting a depth test when you don't have a depth buffer available, not binding any value to an attribute or uniform, or binding multiple textures with different dimensions to the same framebuffer.
So, instead of the OpenGL default of "oh, something bad happened, better not show the programmer any errors ever so he loses as many hours on this as possible", you get a nice Rust panic!() that crashes the program, hopefully with a helpful error message.
 

Koren

Member
Well he took the address of it, so at that point the compiler isn't allowed to keep it in a register anymore.
Indeed... I'm just curious about when he does this exactly (just before calling cout or right at the start of the function). Not that it's important, but I'm the kind of person that love exploring those darkest bits of implementation of compilers/interpreters...


On a similar matter, I spent a lot of time two weeks ago trying to figure how cpython was dealing with a mutation of a slice of a list if the right-hand is a generator that access the list itself.

I discovered that, in some cases
Code:
L[0:len(L)] = my_gen
and
Code:
for i, e in enumerate(my_gen) : L[i] = e
don't give the same result...

For example, when you build my_gen like this:
Code:
def f(L) :
        for i in range(len(L)) :
            yield L[-i-1]
            
my_gen = f(L)

(the for/enumerate gives you a mirrored list, the slice/mutation gives a reversed list, both in 2.7 and in 3)

I would have expected the first to act like the second, but for some reason, it seems that in the first case, cpython first build a temporary list with the values spitted by the generator, then uses the list to perform the mutation.


Granted, I'd never do anything like this in real situations, and looking at the source of cpython would probably give at least an answer on the how (which I mostly figured), but I'd like to have an answer on the "why", because it seems like a waste to me.

And I've found nothing in the documentation about this yet...
 
Indeed... I'm just curious about when he does this exactly (just before calling cout or right at the start of the function). Not that it's important, but I'm the kind of person that love exploring those darkest bits of implementation of compilers/interpreters...

In order to give it an address it has to allocate stack space for it. The only way to do that is to give it space with the rest of the local variables, since if it were to allocate this space right before the call to cout there could have been other calls.

In other words, all stack space s function needs is allocated up front. The only question is when does it initialize this stack slot from the register. It's probably up to the compiler and the level of optimization enabled. It's not uncommon in an optimized build for variables to be in different locations at different points in the function, but in a build with optimization off I would expect it to be initialized at the start of the function

Speaking of Python, I tracked down a really messed up bug the other day. One component of the project I work on is a pretty involved Python extension module. Naturally, many of the native methods implemented in the extension module allocate unmanaged resources that need to be freed. In one case it was mmap'ing a file, which on Windows locks the file and prevents it from being overwritten. So we found a situation where when an exception was thrown, code later on was not able to overwrite the file. We stared at the code forever but couldn't figure it out because stepping through the exceptional codepath nothing interesting was really happening. But when the exception was finished being handled, we just couldn't delete the file.

We started using some nasty python tricks like storing global weakrefs to unmanaged resources and sure enough we found out that some of them weren't getting cleaned up when the exception was thrown. Then I learned about gc.getreferrers() and from there was able to reverse engineer the entire object graph to the point that was responsible for not releasing this. And it was something like there was an exception object which was holding onto the call stack where the exception occurred, and that call stack held onto references to each frame in the call stack, and the deepest frame was holding onto references to all its local variables, one of which was the unmanaged resource. But the weird thing was this was still around even *after* the exception was done being handled. It was like:

Code:
try:
    foo()
exception
    pass

# the entire object graph of the exceptional codepath starting from foo() is still around at this point.

Turns out that sys.exc_info() returns info about the last exception that happened in this function, even if the exception is currently finished being handled. So that code sample:

Code:
try:
    foo()
exception
    pass

# sys.exc_info() is valid here!

The solution ended up being to call sys.exc_clear() and gc.collect(), but man that was a messed up bug to track down.
 
Okay I pretty much have the base multithreading program down (in C), pasted code below if anyone notices something off.

Code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define M 3
#define K 2
#define N 3

int A [M][K] = { {1,4}, {2,5}, {3,6} };
int B [K][N] = { {8,7,6}, {5,4,3} };
int C [M][N];

struct v {
   int i; /*row*/
   int j; /*column*/
};

void *runner(void *param); /*thread*/

int main(int argc, char *argv[]) 
{
	int i,j, count = 0;
	for(i = 0; i < M; i++) 
	{
		for(j = 0; j < N; j++) 
		{
			/*assigning row and column per thread*/
			struct v *data = (struct v *) malloc(sizeof(struct v));
			data->i = i;
			data->j = j;
			
			pthread_t tid;       
			pthread_attr_t attr; 
			
			pthread_attr_init(&attr);
		
			pthread_create(&tid,&attr,runner,data);
			
			pthread_join(tid, NULL);
			count++;
		}
	}

	/*print matrix*/
	for(i = 0; i < M; i++)
	{
		for(j = 0; j < N; j++) 
		{
			printf("%d ", C[i][j]);
		}
		printf("\n");
   }
}

void *runner(void *param)
{
	struct v *data = param;
	int n, sum = 0;

        /*multiplication*/
	for(n = 0; n< K; n++)
	{
		sum += A[data->i][n] * B[n][data->j];
	}
	C[data->i][data->j] = sum;

	pthread_exit(0);
}

Now I need to figure out how to:

...read matrices A and B from files. Write a separate c program that creates two files for A and B containing random integers in range [1-100]. Then in your program, first read A and B from files and then create threads and calculate the product. Finally store the calculated C matrix in a third file.

Quoted from the below link.

https://www.scribd.com/doc/285477579/derp-pdf

Essentially my next step is to create another program to generate random numbers into the matrices (and edit the above program to account for file input and output). I never used the rand() function (or its C equivalent) before (and I assume that's how you generate random numbers?). Anyone can give me a basic gist on how to approach this next part?
 
Okay I pretty much have the base multithreading program down (in C), pasted code below if anyone notices something off.

Code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define M 3
#define K 2
#define N 3

int A [M][K] = { {1,4}, {2,5}, {3,6} };
int B [K][N] = { {8,7,6}, {5,4,3} };
int C [M][N];

struct v {
   int i; /*row*/
   int j; /*column*/
};

void *runner(void *param); /*thread*/

int main(int argc, char *argv[]) 
{
	int i,j, count = 0;
	for(i = 0; i < M; i++) 
	{
		for(j = 0; j < N; j++) 
		{
			/*assigning row and column per thread*/
			struct v *data = (struct v *) malloc(sizeof(struct v));
			data->i = i;
			data->j = j;
			
			pthread_t tid;       
			pthread_attr_t attr; 
			
			pthread_attr_init(&attr);
		
			pthread_create(&tid,&attr,runner,data);
			
			pthread_join(tid, NULL);
			count++;
		}
	}

	/*print matrix*/
	for(i = 0; i < M; i++)
	{
		for(j = 0; j < N; j++) 
		{
			printf("%d ", C[i][j]);
		}
		printf("n");
   }
}

void *runner(void *param)
{
	struct v *data = param;
	int n, sum = 0;

        /*multiplication*/
	for(n = 0; n< K; n++)
	{
		sum += A[data->i][n] * B[n][data->j];
	}
	C[data->i][data->j] = sum;

	pthread_exit(0);
}

Now I need to figure out how to:



Quoted from the below link.

https://www.scribd.com/doc/285477579/derp-pdf

Essentially my next step is to create another program to generate random numbers into the matrices (and edit the above program to account for file input and output). I never used the rand() function (or its C equivalent) before (and I assume that's how you generate random numbers?). Anyone can give me a basic gist on how to approach this next part?

Thought you were using C++ threads. I really don't recommend getting into the habit of using pthreads since they are not portable
 
Thought you were using C++ threads. I really don't recommend getting into the habit of using pthreads since they are not portable

Yeah, well the issue is I didn't want to deviate too much from what my professor shows in the book/lecture which is all C (as poor as a professor she is, I'd like to have some grasp on what she's teaching). Been collaborating with some classmates of mine and it was easier to work in C. Later on I might plan to convert this into C++.

Edit: I've spend the last hour or so figuring out how to do this but to no avail. This new program I'm trying to create is supposed to ask the user for the dimensions of two matrices which is then filled out with random numbers and outputted to two different files (one for each matrix). Said files are then read by the main program (which I wrote above) and both matrices are stored within. The big problem I'm having is figuring out how to carry the dimensions over from one program to the other. I can't exactly put the dimensions into to the text output file 'lest that screw up the matrices right?
 

Kalentan

Member

Hey dude Koren. I just wanted to thank you. Seriously. This assignment was causing me a lot of annoyance and stress. Seriously, thank you dude.

Edit: Koren, so I've been trying your code and was going to mix it with mine. But... It doesn't work with 0xaaaaaaaa and 0x24924924. Which is what the assignment needed. D:

Seriously you would be surprised how not a single google links knows how to do it. Hell, the one post I saw that someone asked, they never said how they did it.
 

Slavik81

Member
I recently built the Python package d2lmf to help mark student assignments submitted via D2L. It's currently licensed MIT, but I am considering switching to GPL.

The main benefit is that then I could import GPL libraries, such as patool. I don't think there's much downside to switching, as I only really care about building a cli. I have no real desire to provide a Python library interface.

I'm not terribly familiar with GPL in the context of Python, so I'd appreciate any input.
 
Yeah, well the issue is I didn't want to deviate too much from what my professor shows in the book/lecture which is all C (as poor as a professor she is, I'd like to have some grasp on what she's teaching). Been collaborating with some classmates of mine and it was easier to work in C. Later on I might plan to convert this into C++.

Edit: I've spend the last hour or so figuring out how to do this but to no avail. This new program I'm trying to create is supposed to ask the user for the dimensions of two matrices which is then filled out with random numbers and outputted to two different files (one for each matrix). Said files are then read by the main program (which I wrote above) and both matrices are stored within. The big problem I'm having is figuring out how to carry the dimensions over from one program to the other. I can't exactly put the dimensions into to the text output file 'lest that screw up the matrices right?

Just figure it out from the input file. If you format it as a nice matrix, then the number of spaces and number of newlines should tell you the dimensions
 

Hypron

Member
Hey everyone,

I'm not sure if this is the best place to ask this, but is there anyone here with Simulink and LabVIEW experience? (Any Control Systems Engineer lurking here? :p)

I was wondering if it's possible to integrate the two.

Let's say you have a robot controlled by a NI device like a myRIO.

All the low level sensor/actuator interfacing stuff would be written in LabVIEW.

The idea I had was to have a controller block in the LabVIEW program that is somehow "linked" to Simulink.

For example, you would write the controller in Simulink and use it to perform simulations. Then you are happy with the performance, you click a button which compiles the controller and does whatever is necessary so that the controller block in the LabVIEW program is updated with the new controller code.

Then you could just compile and run that entire LabVIEW program on the myRIO.

I did some google research and I think it might be possible. For example it's possible to convert a Simulink simulation model to a LabVIEW one (but I wouldn't really trust tools like that too much from experience, and I'm not sure it's possible to automatically update the converted code). You can also communicate between a LabVIEW program and a Simulink simulation &#8212; but that's not practical, I'd like all the code to run on the myRIO. So yeah, in summary I couldn't find a source that did exactly what I described above.

Cheers!
 

Slavik81

Member
I've been playing around with glium over the last couple of days and it's really, really cool. It's an OpenGL library for Rust that wraps the ugly beast that is the OpenGL state machine and exposes a nice Rust-idiomatic API. The coolest thing about is the following (quote from the Github page):

So, instead of the OpenGL default of "oh, something bad happened, better not show the programmer any errors ever so he loses as many hours on this as possible", you get a nice Rust panic!() that crashes the program, hopefully with a helpful error message.
You can do something similar for other OpenGL programs by running with ApiTrace. It inserts a layer between your program and your OpenGL implementation using dll injection, saving every call to disk. You can then analyse it after, replaying the trace to view your call parameters or buffer contents at any point in the execution of your program. It will automatically highlight calls with errors, and will warn about calls with poor performance.

More people should know about ApiTrace. As you say, graphics stuff can be a pain to debug if all you have is glGetError().

One of the things I like about Vulkan is that it's being designed from the start with hooks for validation and debug tooling. They've really taken the need to heart.
 

Koren

Member
Hey dude Koren. I just wanted to thank you. Seriously. This assignment was causing me a lot of annoyance and stress. Seriously, thank you dude.
You're most welcome, I hadn't played with assembly for some time, although I really like it, and my students have a two-weeks break, so I've some time.

I just hope you understand the best of it, or it's not really useful...

Edit: Koren, so I've been trying your code and was going to mix it with mine. But... It doesn't work with 0xaaaaaaaa and 0x24924924. Which is what the assignment needed. D:
I'm pretty sure it does, but maybe not they way you tried it.

I'd say I've been a little farther than what was requested (since the input part isn't clear), and if you enter the sets, you should enter
1010 1010 1010 1010 1010 1010 1010 1010
and
0010 0100 1001 1101 0101 1001 0010 0100

But you can replace both
Code:
        la $t0, readSet      # Use readSet to read the set from standard input
        jalr $s6, $t0
by
entering directly the values (0xaaaaaaaa and 0x24924924) into $s3 and you'll be fine.

entering the values is tricky, though, since I think you can't enter a 32-bits immediate, and you have to use
Code:
lui $s3, 0xaaaa
ori $s3, $s3, 0xaaaa
and
Code:
lui $s3, 0x2492
ori $s3, $s3, 0x4924
(I have to check it works)

But give me ten minutes, I modify the code to show you how to decode the values in hexa instead of binary.

Thought you were using C++ threads. I really don't recommend getting into the habit of using pthreads since they are not portable
Hey, there's at least a couple advantages working with Cygwin ;) There's also a win32-pthread port. I wouldn't say it's the most portable thing, but I've used them for years on Linux, Windows (and I think they worked in OS-X) without problems...

In order to give it an address it has to allocate stack space for it. The only way to do that is to give it space with the rest of the local variables, since if it were to allocate this space right before the call to cout there could have been other calls.
You can still allocate space on the stack any time *inside* the function... You could technically perform the first cout call, for example, before reserving stack for j.

Speaking of Python, I tracked down a really messed up bug the other day.
Thanks for typing this long report. It may be useful later. Tricky, indeed... The fact that Python has a weak support of variable localisation has already caused me troubles, too. It's handy sometimes to have values available outside of loops and such, but it can also be bothering, especially with GC and ressource releasing.

I'm not sure if this is the best place to ask this, but is there anyone here with Simulink and LabVIEW experience? (Any Control Systems Engineer lurking here? :p)

I was wondering if it's possible to integrate the two.
Can't help you directly, but if I understand well what you're doing, I can confirm it's possible, I've help a colleague doing something like this two years ago.
 

Koren

Member
Hey dude Koren. I just wanted to thank you. Seriously. This assignment was causing me a lot of annoyance and stress. Seriously, thank you dude.

Edit: Koren, so I've been trying your code and was going to mix it with mine. But... It doesn't work with 0xaaaaaaaa and 0x24924924. Which is what the assignment needed. D:

Seriously you would be surprised how not a single google links knows how to do it. Hell, the one post I saw that someone asked, they never said how they did it.

Here is the updated version, with an additional ReadSetHex that scan hexadecimal values instead of binary ones...

The idea is simple: for each char:
- if ASCII < 48, do nothing
- if 48 <= ASCII < 58, the value to add is ASCII-48 (0-9 digit)
- if 58 <= ASCII < 65, do nothing
- if 65 <= ASCII < 71, the value to add is (ASCII-65)+10 (uppercase A-F letter)
- if 71 <= ASCII < 97, do nothing
- if 97 <= ASCII < 103, the value to add is (ASCII-97)+10 (lowercase a-f letter)
- if 103 <= ASCII, do nothing

And before adding each recognized char, you multiply the result by 16 (left shift by 4) to make room for the new 4 bits.

You can use both lowercase and uppercase for hex values. Beside, the leading 0x do nothing, so you can use it or not, your choice.

The only thing you could still improve is mix both ReadSet and ReadSetHex to try to guess whether the used used hex or binary, but that's not needed I'd say ^_^

Code:
##############################################
# Program Name: Test read/write bit string
# Programmer: Koren
# Date: 10/14/2015
#############################################

.data   # Data declaration section

Prompt1: .asciiz "Set1: "
Prompt2: .asciiz "Set2: "
Buffer:  .space 80
Comma:   .asciiz ","
NewLine: .asciiz "\n"
Union:   .asciiz "Union of sets: "
Inters:  .asciiz "Intersection of sets: "
Result:  .asciiz "The set is: "
Bye:     .asciiz "Have a nice day."

.globl  main
.text
               
main:
        li $v0, 4            # System call code for Print
        la $a0, Prompt1      # Load adddress of prompt into $a0
        syscall
       
        la $t0, readSetHex   # Use readSet to read the set from standard input
        jalr $s6, $t0           
        move $s1, $s3        # Store a copy of the result in $s1
        
        li $v0, 4            # System call code for Print String
        la $a0, Result       # Load address of msg into $a0
        syscall              # Print the string
        
        la $t0, printSet     # Use printSet to print the first set
        jalr $s6, $t0
        
        li $v0, 4            # System call code for Print
        la $a0, Prompt2      # Load adddress of prompt into $a0
        syscall
       
        la $t0, readSetHex   # Use readSet to read the set from standard input
        jalr $s6, $t0           
        move $s2, $s3        # Store a copy of the result in $s2
        
        li $v0, 4            # System call code for Print String
        la $a0, Result       # Load address of msg into $a0
        syscall              # Print the string
        
        la $t0, printSet     # Use printSet to print the second set
        jalr $s6, $t0
        
        
        li $v0, 4            # System call code for Print String
        la $a0, Union        # Load address of msg into $a0
        syscall              # Print the string

        or $s3, $s1, $s2     # Compute the union
        
        la $t0, printSet     # Use printSet to print the union
        jalr $s6, $t0
        
        
        li $v0, 4            # System call code for Print String
        la $a0, Inters       # Load address of msg into $a0
        syscall              # Print the string
        
        and $s3, $s1, $s2    # Compute the intersection

        la $t0, printSet     # Use printSet to print the union
        jalr $s6, $t0
        
        li $v0, 4            # System call code for Print String
        la $a0, Bye          # Load address of msg into $a0
        syscall
        
        li $v0, 10           # Terminate program and
        syscall              # Return control to the system

##############################################################

readSet: # Read from standard input, the result will be in $s3, use $t3-$t7

        li $v0, 8
        la $a0, Buffer
        la $a1, 80
        syscall
        
        move $s3, $a0
        
        li $t7, 0x0     # Will contain the bit string
        li $t6, 0x30    # ASCII value for '0'
        li $t5, 0x31    # ASCII value for '1'
        li $t4, 0x0     # End-of-string character
 
rloop : lb $t3, ($s3)
        beq $t3, $t4, endread
        beq $t3, $t5, one
        beq $t3, $t6, zero

        b next

one :   sll $t7, $t7, 1
        ori $t7, $t7, 0x1
        b next

zero :  sll $t7, $t7, 1

next :  addi $s3, $s3, 1
        b rloop

endread : move $s3, $t7
        jr $s6

##############################################################

readSetHex: # Read from standard input, the result will be in $s3, use $t3-$t7

        li $v0, 8
        la $a0, Buffer
        la $a1, 80
        syscall
        
        move $s3, $a0
        
        li $t7, 0x0     # Will contain the bit string
        li $t4, 0x0     # End-of-string character
 
hloop : lb $t3, ($s3)
        beq $t3, $t4, endreadh # Null char, end of string!
        
        li $t5, 0x30       # Remove 48 to the char, which is ASCII of '0'
        sub $t6, $t3, $t5  # Result in $t6
        bltz $t6, nexth    # ASCII < 48 -> do nothing

        li $t5, 0x0a       # Remove 10 more
        sub $t2, $t6, $t5  # Result in $t2        
        bgez $t2, notdigit # It it's 58 or more, it's not a 0-9 digit
        
digit : sll $t7, $t7, 4
        or  $t7, $t7, $t6  # Add the digit
        b nexth            # Next char!

notdigit : li $t5, 0x41    # Remove 65 to the char, which is ASCII of 'A'
        sub $t6, $t3, $t5  # Result in $t6
        bltz $t6, nexth    # ASCII < 65 -> do nothing
        
        li $t5, 0x06       # Remove 6 more
        sub $t2, $t6, $t5  # Result in $t2
        bgez $t2, notupper # It it's 71 or more, it's not a A-F digit

upper : sll $t7, $t7, 4
        or  $t7, $t7, $t6  # Add the A-F digit
        addi $t7, 0x0a
        b nexth            # Next char!

notupper : li $t5, 0x61    # Remove 97 to the char, which is ASCII of 'a'
        sub $t6, $t3, $t5  # Result in $t6
        bltz $t6, nexth    # ASCII < 97 -> do nothing

        li $t5, 0x06       # Remove 6 more
        sub $t2, $t6, $t5  # Result in $t2
        bgez $t2, nexth    # It it's 103 or more, it's not a a-f digit

lower : sll $t7, $t7, 4
        or  $t7, $t7, $t6  # Add the a-f digit
        addi $t7, 0x0a

nexth : addi $s3, $s3, 1
        b hloop

endreadh : move $s3, $t7
        jr $s6

##############################################################

printSet: # Assume the set to print is a word in $s3, will modify $t2-$t7

        move $t6, $s3        # Move the set into $t6
        
        li $t2, 0x1          # A one to test the results
        li $t3, 0x0          # A zero to test the results
        li $t4, 0x1          # The number of the set
        li $t7, 0x20         # Max number of sets

loop:   and $t5, $t6, $t2    # Test the lowest bit                
        beq $t5, $t3, check  # Result is non-zero only if the bit is set

        li $v0, 1            # System call code for integer print
        move $a0, $t4        # Set integer to be printed
        syscall              # print the integer

        li $v0, 4            # System call code for Print String
        la $a0, Comma        # Load address of msg into $a0
        syscall              # Print the string
 
check:  beq $t7, $t4, back   # check whether it was the last set
        srl $t6, $t6, 1      # shift the bit one place right to test next bit
        addi $t4, $t4, 1     # add 1 to the set number
        b loop

back:   li $v0, 4            # System call code for Print String
        la $a0, NewLine      # Load address of msg into $a0
        syscall              # Print the string
        jr $s6
           
##############################################################

This gives:
Code:
Set1: 0xaaaaaaaa
The set is: 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,
Set2: 0x24924924
The set is: 3,6,9,12,15,18,21,24,27,30,
Union of sets: 2,3,4,6,8,9,10,12,14,15,16,18,20,21,22,24,26,27,28,30,32,
Intersection of sets: 6,12,18,24,30,
Have a nice day.
 

Massa

Member
I recently built the Python package d2lmf to help mark student assignments submitted via D2L. It's currently licensed MIT, but I am considering switching to GPL.

The main benefit is that then I could import GPL libraries, such as patool. I don't think there's much downside to switching, as I only really care about building a cli. I have no real desire to provide a Python library interface.

I'm not terribly familiar with GPL in the context of Python, so I'd appreciate any input.

The MIT license is GPL compatible so you're fine already.
 

Kalentan

Member
Hey Koren. I managed to also get the whole aspect of: "Is 20 in the set?" from the question. :D I tested it on a variety of sets and it worked flawlessly. Said 20 was in the set if 20 existed and said 20 wasn't in the set if it didn't.
 

Koren

Member
Hey Koren. I managed to also get the whole aspect of: "Is 20 in the set?" from the question. :D I tested it on a variety of sets and it worked flawlessly. Said 20 was in the set if 20 existed and said 20 wasn't in the set if it didn't.
Great... Congratulations!

Anything else I could help with? Or is everything clear enough?
 

Kalentan

Member
Great... Congratulations!

Anything else I could help with? Or is everything clear enough?

Yeah, everything was super clear. I think the motto of this assignment is take better notes. I think I need to write down more than just what the teacher writes on the board but also what he says. Since he did say we went over the assignment.
 

Koren

Member
Yeah, everything was super clear. I think the motto of this assignment is take better notes. I think I need to write down more than just what the teacher writes on the board but also what he says.
^_^

Actually, that's a real problem with algorithmic courses (and even more with assembly, I'd say). When I teach physics, I let my students take notes, it usually works pretty well as long as I let them some time to listen so that they're not writing all the time without paying any attention.

But in computer science, I'm printing the whole thing (with fully written explainations) and let them annotate the codes... I've discovered it's virtually impossible to pay attention to discussions and write the code snippets without errors, let alone all explanations. In fact, they may have twenty lines to write in one hour, and I still find mistakes in those :/
 
But you still need something like those to avoid abuses...

GPL being illegal here make things slightly harder :/

GPL is a good way to guarantee that no corporation or startup will use your code unless it's absolutely vital to their business and there is no other way that they can do so.

Slotting in my own personal opinion here, GPL is kind of, sort of a good way of allowing people to see your code but guaranteeing that they can't monetize it to a very significant degree.

In practice, I've seen several small, one-or-two person developers steal code like GPL licensed chess engines for mobile apps as a quick way of getting software onto the App/Google Play Store. In some instances you can e-mail them and they'll give you something without instructions that was probably derived from that product at one time. I've seen products like a ZFS extension for OS X that used the copyleft CDDL license do exactly that. It works under the terms of the license, but it's unlikely that it's useful to anybody in that form.

In my opinion, I think Apache and BSD are the best licenses, at least then you can write code, open source it, and use it for your job, whatever job, later on. And you don't have to worry about having lawyers on hand to sue smaller developers for using code you wrote later on, and there's a fair amount of goodwill that comes with releasing code under a liberal license among your fellow developers at conferences, industry parties, etc etc etc.

And I don't think BSD/MIT/Apache keep away corporate contributors. On the contrary, LLVM is doing really well as a corporate friendly, liberally licensed open source project, to the point where it's influencing projects far beyond its originally intended means.

GPL had a pretty strong place in history with Linux in the early days of open source licensing. Now that open source is more widely practiced, contributed and used, I don't think there's as strong of a case in favor of copyleft as there used to be. Nine times out of ten, there's something as good in the liberally licensed space when there's copyleft code, and most developers prefer to never, ever even read the copyleft code lest they accidentally end up writing something that they could be sued for.*

* - Might be an exaggeration that this could actually happen, but that tends to be a case I've heard against even reading the GPLed stuff. Somehow.
 

Koren

Member
Where's that?
France... One of the main reasons is that you can't completely forfeit your rights on anything you create (and also, you can't deny any responsability for it). It's not really an issue in practice, but I'm not sure how it would work if it was challenged in court. There's also the issue that contracts (and it's considered like a contract) should be written in the official language.

But we have a couple of set of perfectly fine variants, totally GPL-compatible, some really close to BSD ones. So it isn't a big issue (but when you work for research labs or companies, you'd better choose something that won't have issue with local law).

I'm pretty sure it's not the only place in the world where minor adjustements have to be made. It's just that the three biggest research organisms here took the time to discuss the matter with lawyers and come to a solution.

GPL is a good way to guarantee that no corporation or startup will use your code unless it's absolutely vital to their business and there is no other way that they can do so.
Garantee, probably not (there's too many examples even with companies), but at least you have the possibility to defend yourself. So I think it's needed.

I also like BSD (or the BSD variant available here)...

At the end of the day, ownership, copyright, sharing and everything code-related is a can of worms. :/
 
Code:
#include<stdio.h>
#include<stdlib.h>
 
#define ROW 10000
#define COLUMN 10000
 
void writeMatrixtoFile(int row, int column, int mtrx[row][column]);
 
int A[ROW][COLUMN];
int B[ROW][COLUMN];
int i, j;

//------------------------------------------------------------------------------
//Main function
 
int main()
{
	int nrows, ncol;

	printf("Please enter the number of rows and columns for the matrix:\n");
	printf("number of rows: ");
	scanf("%d", &nrows);
	printf("number of columns: ");
	scanf("%d", &ncol);

	for(i=0;i<nrows;i++){
		for(j=0;j<ncol;j++){
			A[i][j]=rand() % 100 + 1;
		}
	}
 
    writeMatrixtoFile(ROW, COLUMN, A[ROW][COLUMN]);
 
    return 0;
}

//------------------------------------------------------------------------------
//This function is for writing a matrix into a file
void writeMatrixtoFile(int row, int column, int mtrx[row][column])
{
    FILE *matrix=fopen("A.txt", "w");
    int a=0, b=0;
 
    for(a=0;a<row;a++)     
    {
        for(b=0;b<column;b++)  
        {              
            fprintf(matrix, "%lf\t", mtrx[a][b]);
        }
        fprintf(matrix, "\n");
    } 
 
    fclose(matrix);
}

Getting segmentation faults, worst error ever. Anyone help?
 
And I don't think BSD/MIT/Apache keep away corporate contributors. On the contrary, LLVM is doing really well as a corporate friendly, liberally licensed open source project, to the point where it's influencing projects far beyond its originally intended means.

In the web front pretty much everything is MIT licensed and all the big players participate heavily too for the better of everyone.
 

Koren

Member
Getting segmentation faults, worst error ever. Anyone help?
I'm not surprised it segfaults, I'm surprised it even compiles??

When you write
Code:
writeMatrixtoFile(ROW, COLUMN, A[ROW][COLUMN])
A[ROW][COLUMN] is not the table A, it's the 10000th element of the 10000th raw of A, which is technically outside of the table. Thus, segfault possible. You should have written only A.

But there's plently of others issues. By writing ROW and COLUMN in the same line instead of nrows and ncol, you'll get the wrong number of rows/columns in the file (the ones in the #define). :/

Code:
writeMatrixtoFile(nrows, ncol, A)
could be a good start.

Beside, by writing this:
Code:
void writeMatrixtoFile(int row, int column, int mtrx[row][column])
(the row in mtrx is useless, if I'm not mistaken, btw)
you try to pass a table of variable length. The problem is that A is NOT of variable length, it's of fixed length. And should you managed to pass it as variable size, you won't get the correct values in the loops, since the function will assume the wrong width for the table...


This is a really, really awful way to create matrix of variable size, too. You'll always have the largest size in memory, even for a 2x2 matrix, and values will be scattered in the table, thus giving really bad performances.


I'd rather change
Code:
#define ROW 10000
by
Code:
const int ROW=10000;

Because I'm reluctant to use the preprocessor for this kind of values, it produces a lot of possible issues...
 
Hey, there's at least a couple advantages working with Cygwin ;) There's also a win32-pthread port. I wouldn't say it's the most portable thing, but I've used them for years on Linux, Windows (and I think they worked in OS-X) without problems....

That's a disadvantage of using cygwin imo, because it lures you into a false sense of portability that incidentally also performs like garbage on Windows since it tries to mimic posix semantics under a threading model that doesn't lend itself well to that. That's the problem with cygwin in general. It makes it too easy to produce crap.

threading support was added to the c++ standard library for a reason, that's what people should be using.

It's rare anymore to find places where C++ is banned and everything must be strict C
 

Koren

Member
threading support was added to the c++ standard library for a reason, that's what people should be using.
I agree, but it's quite recent... I'm pretty sure it wasn't available when I needed thread for the first time.

And should I find a software that use pthreads, compiling it with some posix compatibility layer is easier than rewriting it to support a different kind of threads...

That's the problem with cygwin in general. It makes it too easy to produce crap.
I tend to avoid Cygwin compiler chain (I still enjoy it as console replacement, though). But I'm not sure it's really "crap".

Yes, it use an akward layer between POSIX semantics and Windows, but in some cases, I still find it handy to have this solution available. Most of the time, performances won't really be a huge issue anyway.

Should I badmouth a bit, Cygwin is not worse than JVM ;)


(about banning C++, the most obvious example I could come with is Linus position about the Linux kernel, not the most obvious thing you would port on Windows ;) )
 
Top Bottom