# New Ticket Created by  Rob Hoelz 
# Please include the string:  [perl #126183]
# in the subject line of all future correspondence about this issue. 
# <URL: https://rt.perl.org/Ticket/Display.html?id=126183 >


See subject and the attached script.

To run the attached test script, you'll need to build a patched MoarVM (apply 
meminfo-moar.patch and run tools/update_ops.p6), a patched NQP (apply 
meminfo-nqp.patch), and Rakudo using those two patched programs.  The patch 
adds support for a meminfo() op that reports memory using mallinfo(), which I 
believe is glibc-specific.

The test script prints out memory usage each second; you only really need to 
care about the first column, which is the amount of memory allocated not using 
mmap.  I have also attached an Octave program I used to plot the data from the 
script; I have attached one of the plots as well.

I believe the problem is here:

https://github.com/MoarVM/MoarVM/blob/51dcbe4a41d5e2853ff32c9d9632c53a5ae44340/src/6model/reprs/MVMCallCapture.c#L61

and here:

https://github.com/MoarVM/MoarVM/blob/51dcbe4a41d5e2853ff32c9d9632c53a5ae44340/src/core/args.c#L62

effective_callsite points to a new callsite object, which is only free'd if 
it's not equal to the original callsite object.  However, further down in 
args.c, callsite is set to the location of effective_callsite.
#!/usr/bin/env perl6

use nqp;

sub noop(*@args) {}
sub noop-subsig(*@args ($, *@)) {}

sub for-a-second-keep-doing(&code) {
    my $done = now + 1;

    while now < $done {
        code();
    }
}

say(nqp::meminfo());
for 1..60 {
    for-a-second-keep-doing {;
        #noop('cat');
        noop-subsig('cat');
    };
    say(nqp::meminfo());
}

=begin Instructions

Build a MoarVM and NQP using the patches attached to this RT ticket,
and use them to build a Rakudo.  The patches implement a meminfo opcode,
which returns a space-delimited string containing the values returned
by C<mallinfo()>, which, AFAIK, is glibc-specific.

Uncomment the C<noop()> call above, run this script, storing the output
to some file.

Restore the comment on C<noop()>, uncomment the call to C<noop-subsig()>.
Run and store output to a different file.

I used GNU Octave to plot the data; use whatever software you feel comfortable
with, or just read the output, if that's your thing. =)  I've attached the
Octave script I used to plot this in case you want to use that.  We only really
need to care about the first column, which is the amount of memory allocated
by means other than C<mmap()>.

Also attached are images that I generated using this setup; one has C<MVM_SPESH_DISABLE>
and C<MVM_JIT_DISABLE> on, one does not.

=end Instructions
diff --git a/src/core/interp.c b/src/core/interp.c
index c1c5f63..37972f4 100644
--- a/src/core/interp.c
+++ b/src/core/interp.c
@@ -2,6 +2,8 @@
 #include <math.h>
 #include "platform/time.h"
 
+#include <malloc.h>
+
 /* Macros for getting things from the bytecode stream. */
 #define GET_REG(pc, idx)    reg_base[*((MVMuint16 *)(pc + idx))]
 #define GET_LEX(pc, idx, f) f->env[*((MVMuint16 *)(pc + idx))]
@@ -5117,6 +5119,21 @@ void MVM_interp_run(MVMThreadContext *tc, void 
(*initial_invoke)(MVMThreadContex
                 MVM_cross_thread_write_check(tc, obj, blame);
                 goto NEXT;
             }
+            OP(meminfo): {
+                char buffer[256];
+                struct mallinfo mi;
+
+                mi = mallinfo();
+
+                snprintf(buffer, 255, "%d %d %d %d %d %d %d %d %d %d",
+                    mi.arena, mi.ordblks, mi.smblks,
+                    mi.hblks, mi.hblkhd, mi.usmblks,
+                    mi.fsmblks, mi.uordblks, mi.fordblks, mi.keepcost);
+                buffer[255] = '\0';
+                GET_REG(cur_op, 0).s = MVM_string_ascii_decode(tc, 
tc->instance->VMString, buffer, strlen(buffer));
+                cur_op += 2;
+                goto NEXT;
+            }
 #if MVM_CGOTO
             OP_CALL_EXTOP: {
                 /* Bounds checking? Never heard of that. */
diff --git a/src/core/oplist b/src/core/oplist
index 870ef22..7db22f4 100644
--- a/src/core/oplist
+++ b/src/core/oplist
@@ -841,3 +841,5 @@ prof_allocated   .s r(obj)
 
 # Cross-thread write analysis logging instruction.
 ctw_check        .s r(obj) int16
+
+meminfo        w(str)
diff --git a/src/vm/moar/QAST/QASTOperationsMAST.nqp 
b/src/vm/moar/QAST/QASTOperationsMAST.nqp
index faa62b4..811bb7d 100644
--- a/src/vm/moar/QAST/QASTOperationsMAST.nqp
+++ b/src/vm/moar/QAST/QASTOperationsMAST.nqp
@@ -2809,6 +2809,8 @@ 
QAST::MASTOperations.add_core_moarop_mapping('mvmendprofile', 'endprofile');
 # MoarVM-specific GC ops
 QAST::MASTOperations.add_core_moarop_mapping('force_gc', 'force_gc');
 
+QAST::MASTOperations.add_core_moarop_mapping('meminfo', 'meminfo');
+
 sub resolve_condition_op($kind, $negated) {
     return $negated ??
         $kind == $MVM_reg_int64 ?? 'unless_i' !!
#!/usr/bin/env octave

% in this plot, the red line is the arena (non-mmap'd allocated data) usage for
% a sub without a subsignature, and the blue line is the arena usage for a sub
% with a subsignature

args = argv();

BasicData  = dlmread(args{1}, ' ');
SubsigData = dlmread(args{2}, ' ');

hold on;
plot(BasicData(:, 1), 'r-');
plot(SubsigData(:, 1), 'b-');
pause();

Reply via email to