Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save titsuki/11a483c0aaa509c24407878491698f51 to your computer and use it in GitHub Desktop.
Save titsuki/11a483c0aaa509c24407878491698f51 to your computer and use it in GitHub Desktop.
See the following codes and results.
*** codes ***
* t/05-pointer.c
----
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "05-pointer.h"
#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT extern
#endif
double dot(struct Feature* lhs, struct Feature* rhs) {
double sum = 0.0;
while(lhs->index != -1 && rhs->index != -1) {
if (lhs->index == rhs->index) {
sum += lhs->value * rhs->value;
lhs++;
rhs++;
}
else if (lhs->index < rhs->index) {
lhs++;
}
else {
rhs++;
}
}
return sum;
}
----
*t/05-pointer.h
----
#if ! defined(HEADER_POINTER_H)
#define HEADER_POINTER_H
#ifdef __cplusplus
extern "C" {
#endif
struct Feature {
int index;
double value;
} Feature;
double dot(struct Feature*, struct Feature*);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
#endif /* HEADER_POINTER_H */
----
* t/CompileTestLib.pm
----
unit module CompileTestLib;
my @cleanup; # files to be cleaned up afterwards
sub compile_test_lib($name) is export {
my ($c_line, $l_line);
my $VM := $*VM;
my $cfg := $VM.config;
my $libname = $VM.platform-library-name($name.IO);
if $VM.name eq 'moar' {
my $o = $cfg<obj>;
# MoarVM exposes exposes GNU make directives here, but we cannot pass this to gcc directly.
my $ldshared = $cfg<ldshared>.subst(/'--out-implib,lib$(notdir $@).a'/, "--out-implib,$libname.a");
$c_line = "$cfg<cc> -c $cfg<ccshared> $cfg<ccout>$name$o $cfg<cflags> t/$name.c";
$l_line = "$cfg<ld> $ldshared $cfg<ldflags> $cfg<ldlibs> $cfg<ldout>$libname $name$o";
@cleanup = << "$libname" "$name$o" >>;
}
elsif $VM.name eq 'jvm' {
$c_line = "$cfg<nativecall.cc> -c $cfg<nativecall.ccdlflags> -o$name$cfg<nativecall.o> $cfg<nativecall.ccflags> t/04-nativecall/$name.c";
$l_line = "$cfg<nativecall.ld> $cfg<nativecall.perllibs> $cfg<nativecall.lddlflags> $cfg<nativecall.ldflags> $cfg<nativecall.ldout>$libname $name$cfg<nativecall.o>";
@cleanup = << $libname "$name$cfg<nativecall.o>" >>;
}
else {
die "Unknown VM; don't know how to compile test libraries";
}
shell($c_line);
shell($l_line);
}
sub compile_cpp_test_lib($name) is export {
my @cmds;
my $VM := $*VM;
my $cfg := $VM.config;
my $libname = $VM.platform-library-name($name.IO);
@cleanup = $libname;
if $*DISTRO.is-win {
@cmds = "cl /LD /EHsc /Fe$libname t/$name.cpp",
"g++ --shared -fPIC -o $libname t/$name.cpp",
}
else {
@cmds = "g++ --shared -fPIC -o $libname t/$name.cpp",
"clang++ -stdlib=libc++ --shared -fPIC -o $libname t/$name.cpp",
}
my (@fails, $succeeded);
for @cmds -> $cmd {
my $handle = shell("$cmd 2>&1", :out);
my $output = $handle.out.slurp-rest;
if $handle.out.close.status {
@fails.push: "Running '$cmd':\n$output"
}
else {
$succeeded = 1;
last
}
}
fail @fails.join('=' x 80 ~ "\n") unless $succeeded;
}
END {
# say "cleaning up @cleanup[]";
unlink @cleanup;
}
----
* t/05-pointer.t
----
use v6;
use Test;
use NativeCall;
use lib <lib t>;
use CompileTestLib;
compile_test_lib('05-pointer');
class Feature is repr('CStruct') {
has int32 $.index;
has num64 $.value;
}
my sub dot(Feature, Feature) returns num64 is native("./05-pointer") { * }
my CArray[Feature] $lhs .= new;
my CArray[Feature] $rhs .= new;
$lhs[5] = Feature.new(index => -1, value => 0e0);
$rhs[5] = Feature.new(index => -1, value => 0e0);
for 1..5 -> $index {
$rhs[$index - 1] = Feature.new(index => $index, value => 2.5e0);
$lhs[$index - 1] = Feature.new(index => $index, value => 2.5e0);
}
for ^5 {
is $lhs[$_].value, 2.5e0, "\$lhs[$_].value = 2.5e0";
is $rhs[$_].value, 2.5e0, "\$rhs[$_].value = 2.5e0";
is $lhs[$_].index, $_ + 1, "\$lhs[$_].index = {$_ + 1}";
is $rhs[$_].index, $_ + 1, "\$rhs[$_].index = {$_ + 1}";
}
is dot($lhs[0], $rhs[0]), [+] ((2.5 * 2.5) xx 5);
done-testing;
----
*** results ***
----
$ mi6 test -v t/05-pointer.t
==> Set PERL6LIB=/home/itoyota/Programs/p6-Foo/lib
==> prove -e /home/itoyota/.rakudobrew/bin/../moar-nom/install/bin/perl6 -r -v t/05-pointer.t
t/05-pointer.t ..
ok 1 - $lhs[0].value = 2.5e0
ok 2 - $rhs[0].value = 2.5e0
ok 3 - $lhs[0].index = 1
ok 4 - $rhs[0].index = 1
ok 5 - $lhs[1].value = 2.5e0
ok 6 - $rhs[1].value = 2.5e0
ok 7 - $lhs[1].index = 2
ok 8 - $rhs[1].index = 2p @cleanup[]";
ok 9 - $lhs[2].value = 2.5e0
ok 10 - $rhs[2].value = 2.5e0
ok 11 - $lhs[2].index = 3
ok 12 - $rhs[2].index = 3
ok 13 - $lhs[3].value = 2.5e0
ok 14 - $rhs[3].value = 2.5e0
ok 15 - $lhs[3].index = 4
ok 16 - $rhs[3].index = 4
ok 17 - $lhs[4].value = 2.5e0
ok 18 - $rhs[4].value = 2.5e0
ok 19 - $lhs[4].index = 5
ok 20 - $rhs[4].index = 5
not ok 21 -
# Failed test at t/05-pointer.t line 33
# expected: '31.25'
# got: '6.25'
1..21
# Looks like you failed 1 test of 21
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/21 subtests
Test Summary Report
-------------------
t/05-pointer.t (Wstat: 256 Tests: 21 Failed: 1)
Failed test: 21
Non-zero exit status: 1
Files=1, Tests=21, 1 wallclock secs ( 0.02 usr 0.00 sys + 0.51 cusr 0.06 csys = 0.59 CPU)
Result: FAIL
----
In the above example, dot method accepts entry address of given two vectors and computes the dot product of the values they have.
Hence, in the test case 21, dot($lhs[0],$rhs[0]) should return 31.25e0, where $lhs[0] is the entry address of the CArray[Feature] (the values it has are 2.5e0 xx 5) and $rhs[0] is the entry address of the other CArray[Feature] (the values it has are 2.5e0 xx 5).
However, in fact, it returns 6.25e0.
It seems that dot function in C side receive the entry address of the given vector correctly, but it fails in incrementing the pointer address and points a irrelevant address, because CArray cannot allocate contiguous memory.
I think that NativeCall needs something for allocating contiguous memory.
(I faced this type of error while creating a libsvm bindings for Perl 6: https://github.com/cjlin1/libsvm/blob/master/svm.cpp#L294-L314 )
$ perl6 --version
This is Rakudo version 2016.10-309-g3dcc52b built on MoarVM version 2016.10-71-g9d5c874
implementing Perl 6.c.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment