前端高质量总括之二,多维数组的落到实处

前端高质量总结之二:asm.js & webassembly

2017/10/21 · HTML5 ·
webassembly

原来的作品出处: magicly   

前一篇咱俩说了要消除高质量总结的五个措施,3个是并发用WebWorkers,另四个正是用更底层的静态语言。

二〇一一年,Mozilla的工程师Alon
Zakai在研究LLVM编译器时突发奇想:能否把C/C++编译成Javascript,并且尽量达到Native代码的进程吗?于是他支付了Emscripten编写翻译器,用于将C/C++代码编写翻译成Javascript的三个子集asm.js,品质大约是原生代码的四分之二。大家能够看看这个PPT。

之后Google开发了Portable Native
Client,也是一种能让浏览器运营C/C++代码的技术。
后来估算大家都认为各搞各的13分啊,居然谷歌(Google), Microsoft, Mozilla,
Apple等几家大商店联手同盟开发了贰个面向Web的通用二进制和文本格式的类型,那就是WebAssembly,官网上的介绍是:

WebAssembly or wasm is a new portable, size- and load-time-efficient
format suitable for compilation to the web.

WebAssembly is currently being designed as an open standard by a W3C
Community Group that includes representatives from all major browsers.

所以,WebAssembly相应是二个前景很好的连串。大家得以看一下眼前浏览器的协理意况:
金沙澳门官网 1

  
数组一旦被定义了,它的维数和维界就不会变。因而,除了结构的初阶化和销毁之外,数组只有存取成分和改动成分。数组一般分为行序和列许。一般系统都以用的行许。
以2维数组a[m][n]为例
列序:
a[0][0]  a[1][0] …… a[m-1][0]
………….
a[m-1][0] a[m-1][1] …… a[m-1][n-1]

① 、功用表明:

大家都精晓,字符char类型,占用的上空为8个人,int类型占用空间为15人,当int赋值给char的时候会生出什么样效益呢?处理规则是何许的呢?

安装Emscripten

访问

  1. 下载对应平台版本的SDK

  2. 经过emsdk获取最新版工具

JavaScript

# Fetch the latest registry of available tools. ./emsdk update #
Download and install the latest SDK tools. ./emsdk install latest #
Make the “latest” SDK “active” for the current user. (writes
~/.emscripten file) ./emsdk activate latest # Activate PATH and other
environment variables in the current terminal source ./emsdk_env.sh

1
2
3
4
5
6
7
8
9
10
11
# Fetch the latest registry of available tools.
./emsdk update
 
# Download and install the latest SDK tools.
./emsdk install latest
 
# Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file)
./emsdk activate latest
 
# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh
  1. 将下列添加到环境变量PATH中

JavaScript

~/emsdk-portable ~/emsdk-portable/clang/fastcomp/build_incoming_64/bin
~/emsdk-portable/emscripten/incoming

1
2
3
~/emsdk-portable
~/emsdk-portable/clang/fastcomp/build_incoming_64/bin
~/emsdk-portable/emscripten/incoming
  1. 其他

自家在推行的时候蒙受报错说LLVM本子不对,后来参见文档配置了LLVM_ROOT变量就好了,假若你未曾赶上问题,能够忽略。

JavaScript

LLVM_ROOT = os.path.expanduser(os.getenv(‘LLVM’,
‘/home/ubuntu/a-path/emscripten-fastcomp/build/bin’))

1
LLVM_ROOT = os.path.expanduser(os.getenv(‘LLVM’, ‘/home/ubuntu/a-path/emscripten-fastcomp/build/bin’))
  1. 表明是不是安装好

执行emcc -v,假若设置好会产出如下音信:

JavaScript

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld)
1.37.21 clang version 4.0.0
(
974b55fd84ca447c4297fc3b00cefb6394571d18)
(
9e4ee9a67c3b67239bd1438e31263e2e86653db5) (emscripten 1.37.21 : 1.37.21)
Target: x86_64-apple-darwin15.5.0 Thread model: posix InstalledDir:
/Users/magicly/emsdk-portable/clang/fastcomp/build_incoming_64/bin
INFO:root:(Emscripten: Running sanity checks)

1
2
3
4
5
6
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.37.21
clang version 4.0.0 (https://github.com/kripken/emscripten-fastcomp-clang.git 974b55fd84ca447c4297fc3b00cefb6394571d18) (https://github.com/kripken/emscripten-fastcomp.git 9e4ee9a67c3b67239bd1438e31263e2e86653db5) (emscripten 1.37.21 : 1.37.21)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
InstalledDir: /Users/magicly/emsdk-portable/clang/fastcomp/build_incoming_64/bin
INFO:root:(Emscripten: Running sanity checks)

行序列:
a[0][0]  a[1][0] …… a[m-1][0]
………….
a[0][n-1] a[1][ [n-1 ] …… a[m-1][n-1]
数据一般选拔一连的地址存款和储蓄。总计的主意为 (i, j) = &a + (b) + j;//b
一维成分的个数
加大到多维数组中(j1, j2, j3,…..,jn) = (b2*b3*…*bn * j1 +
b3*b4*…*bn*j2 + …..+bn *jn-1 + jn)
譬如说:已知数组a[5][4][10]。求a[2][3][4] 的地址;
j1=2、j2 = 3、j3 = 4;b1=5、b2=4、b3=10;
a[2][3][4]=b2*b3*j1+b3*j2+j3=4*10*2+10*3+4;

       要成本的Web
Service作用万分简单,正是2个add函数,将五个参数相加,重返其和。

方法一:

Hello, WebAssembly!

创造三个文件hello.c

JavaScript

#include <stdio.h> int main() { printf(“Hello, WebAssembly!\n”);
return 0; }

1
2
3
4
5
#include <stdio.h>
int main() {
  printf("Hello, WebAssembly!\n");
  return 0;
}

编译C/C++代码:

JavaScript

emcc hello.c

1
emcc hello.c

上述命令会变卦一个a.out.js文本,大家能够直接用Node.js执行:

JavaScript

node a.out.js

1
node a.out.js

输出

JavaScript

Hello, WebAssembly!

1
Hello, WebAssembly!

为了让代码运转在网页里面,执行上边发号施令会变动hello.htmlhello.js四个文件,当中hello.jsa.out.js剧情是一点一滴等同的。

emcc hello.c -o hello.html<code>

1
2
emcc hello.c -o hello.html<code>
 

JavaScript

➜ webasm-study md5 a.out.js MD5 (a.out.js) =
d7397f44f817526a4d0f94bc85e46429 ➜ webasm-study md5 hello.js MD5
(hello.js) = d7397f44f817526a4d0f94bc85e46429

1
2
3
4
➜  webasm-study md5 a.out.js
MD5 (a.out.js) = d7397f44f817526a4d0f94bc85e46429
➜  webasm-study md5 hello.js
MD5 (hello.js) = d7397f44f817526a4d0f94bc85e46429

接下来在浏览器打开hello.html,能够看出页面
金沙澳门官网 2

近年来生成的代码都是asm.js,毕竟Emscripten是住户作者Alon
Zakai最早用来扭转asm.js的,默许输出asm.js也就欠缺为奇了。当然,可以因此option生成wasm,会变动八个文本:hello-wasm.html,
hello-wasm.js, hello-wasm.wasm

JavaScript

emcc hello.c -s WASM=1 -o hello-wasm.html

1
emcc hello.c -s WASM=1 -o hello-wasm.html

下一场浏览器打开hello-wasm.html,发现报错TypeError: Failed to fetch。原因是wasm文件是由此XHR异步加载的,用file:////走访会报错,所以大家必要启一个服务器。

JavaScript

npm install -g serve serve

1
2
npm install -g serve
serve

接下来访问http://localhost:5000/hello-wasm.html,就足以见见平日结果了。

下边为代码达成。(以下代码是笔者在ubuntu中概括测试通过。如在别的系统中不或者运维,请见谅。本代码只通过简易的测试,假诺出现难题,请见谅。)
[plain]
/* 
*created by Reage at 2013 March 28 
*description: 数组的贯彻,包含创造、赋值、访问、打字与印刷 

*blog: 
*/ 
#include <stdio.h> 
#include <stdlib.h> 
#include <stdarg.h> 
 
 
#define MAXDIM 4 
 
typedef struct Array 

    int dim; 
    int *ptr; 
    int *bounds; 
    int *base_add; 
}Array; 
 
int array_init(Array *a, int dim, …); 
int array_set_value(Array *a, int value, …); 
int array_print_line(Array *a); 
int array_get_value(Array *a, …); 
void array_destory(Array *a); 
 
int main(int argc, char *argv[]) 

    Array a; 
    int i = 0; 
    int j; 
    int total = 1; 
    array_init(&a, 2, 4, 6); 
     
    for(; i < 4; i++) 
    { 
        for(j = 0; j < 6; j++) 
        { 
            array_set_value(&a, total++, i, j); 
        } 
    } 
 
    array_print_line(&a); 
    for(i = 0; i < 4; i++) 
    { 
        for(j = 0; j < 6; j++) 
        { 
            printf(“%-7d”,array_get_value(&a,  i, j)); 
        } 
        printf(“\n”); 
    } 
    array_destory(&a); 

 
int array_init(Array * a, int dim, …) 

    if(1 > dim || 8 < dim) 
        return -1; 
    a->dim = dim; 
 
    va_list ap; 
    int i; 
    long total = 1; 
 
前端高质量总括之二,多维数组的落到实处。    a->bounds = (int *)malloc(dim * sizeof(int)); 
     
    va_start(ap, dim); 
    for(i = 0; i < dim; i++) 
    { 
        a->bounds[i] = va_arg(ap, int); 
        total *= a->bounds[i]; 
    } 
    va_end(ap); 
 
    a->ptr = (int *) malloc(total * sizeof(int)); 
 
    a->base_add = (int *) malloc(dim * sizeof(int)); 
    a->base_add[dim -1] = 1; 
    i = dim -2; 
    for(; i >= 0; i–) 
    { 
        a->base_add[i] = a->base_add[i+1] *
a->bounds[i+1]; 
    } 
 
    return 0; 

 
#define FREE(x) if(NULL != (x)) free(x) 
 
void array_destory(Array *a) 

    FREE(a->ptr); 
    FREE(a->bounds); 
    FREE(a->base_add); 

 
int array_get_value(Array *a, …) 

    va_list va; 
    va_start(va, a); 
     
    int result = array_get_locate(a, va); 
    if(-1 == result) return -1; 
    return a->ptr[result]; 

 
 
int array_print_line(Array *a) 

    int total = 1; 
    int i = 0; 
    int line ; 
    for(; i < a->dim; i++) 
    { 
        total *= a->bounds[i]; 
    } 
     
    line = total/a->bounds[0]; 
    for(i = 0; i < total; i++) 
    { 
        if(0 == i % line && 0 != i) printf(“\n”); 
        printf(“%-7d”, a->ptr[i]); 
    } 
    printf(“\n”); 
    return 0; 

 
 
int array_get_locate(Array *a, va_list va) 

    int result = 0; 
    int bound; 
    int i; 
    for(i = 0; i < a->dim; i++) 
    { 
        bound = va_arg(va, int); 
        if(0 > bound || bound > a->bounds[i]) 
        { 
            return -1; 
        } 
        result += bound * a->base_add[i]; 
    } 
    return result; 

 
int array_set_value(Array *a, int value, …) 

    if(NULL == a) return -1; 
    va_list va; 
    va_start(va, value); 
 
    int result = array_get_locate(a, va); 
    if( -1 == result) return -1; 
 
    a->ptr[result] = value; 
    return 0; 

 

编写制定如下代码测试:

调用C/C++函数

前面的Hello, WebAssembly!都是main函数直接打出来的,而大家利用WebAssembly的指标是为了高质量计算,做法多半是用C/C++实现有些函数实行耗费时间的总结,然后编写翻译成wasm,暴露给js去调用。

在文件add.c中写如下代码:

JavaScript

#include <stdio.h> int add(int a, int b) { return a + b; } int
main() { printf(“a + b: %d”, add(1, 2)); return 0; }

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int add(int a, int b) {
  return a + b;
}
 
int main() {
  printf("a + b: %d", add(1, 2));
  return 0;
}

有二种办法能够把add办法暴流露来给js调用。

/*
*created by Reage at 2013 March 28
*description: 数组的贯彻,包括创设、赋值、访问、打字与印刷
*
*blog:
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

贰 、C版本的次第:

[html]
#include <stdio.h> 
#include <stdlib.h> 
 
int main() 

char sum; 
int operator1 = 4874; 
//4874 = 0000 0000,0000 0000,0001 0011,0000 1010 hexadecimal 00 00 13
0A 
sum = operator1; 
金沙澳门官网,//situation 1 sum = 0000 0000; cut the higher bits:13 
//situation 2 sum = 0000 1010; cut the lower bits:0A 
printf(“sum = %x\n”,sum); 
 
return EXIT_SUCCESS; 

因此命令行参数暴露API

JavaScript

emcc -s EXPORTED_FUNCTIONS=”[‘_add’]” add.c -o add.js

1
emcc -s EXPORTED_FUNCTIONS="[‘_add’]" add.c -o add.js

留意格局名add前必须加_。 然后我们能够在Node.js当中这么使用:

JavaScript

// file node-add.js const add_module = require(‘./add.js’);
console.log(add_module.ccall(‘add’, ‘number’, [‘number’, ‘number’],
[2, 3]));

1
2
3
// file node-add.js
const add_module = require(‘./add.js’);
console.log(add_module.ccall(‘add’, ‘number’, [‘number’, ‘number’], [2, 3]));

执行node node-add.js会输出5。 要是须求在web页面使用以来,执行:

JavaScript

emcc -s EXPORTED_FUNCTIONS=”[‘_add’]” add.c -o add.html

1
emcc -s EXPORTED_FUNCTIONS="[‘_add’]" add.c -o add.html

下一场在扭转的add.html中到场如下代码:

JavaScript

<button onclick=”nativeAdd()”>click</button> <script
type=’text/javascript’> function nativeAdd() { const result =
Module.ccall(‘add’, ‘number’, [‘number’, ‘number’], [2, 3]);
alert(result); } </script>

1
2
3
4
5
6
7
  <button onclick="nativeAdd()">click</button>
  <script type=’text/javascript’>
    function nativeAdd() {
      const result = Module.ccall(‘add’, ‘number’, [‘number’, ‘number’], [2, 3]);
      alert(result);
    }
  </script>

接下来点击button,就足以看到举办结果了。

Module.ccall会间接调用C/C++代码的办法,更通用的光景是我们收获到2个包裹过的函数,能够在js里面一再调用,那亟需用Module.cwrap,具体细节能够参照文档。

JavaScript

const cAdd = add_module.cwrap(‘add’, ‘number’, [‘number’, ‘number’]);
console.log(cAdd(2, 3)); console.log(cAdd(2, 4));

1
2
3
const cAdd = add_module.cwrap(‘add’, ‘number’, [‘number’, ‘number’]);
console.log(cAdd(2, 3));
console.log(cAdd(2, 4));

#define MAXDIM 4

(1)头文件:SmsWBS.h,注释部分不可少,url部分的IP必须填写当前Linux电脑的IP

#include <stdio.h>
#include <stdlib.h>

概念函数的时候添加EMSCRIPTEN_KEEPALIVE

添加文件add2.c

JavaScript

#include <stdio.h> #include <emscripten.h> int
EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a + b; } int main() {
printf(“a + b: %d”, add(1, 2)); return 0; }

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <emscripten.h>
 
int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
  return a + b;
}
 
int main() {
  printf("a + b: %d", add(1, 2));
  return 0;
}

执行命令:

JavaScript

emcc add2.c -o add2.html

1
emcc add2.c -o add2.html

同样在add2.html中添加代码:

JavaScript

<button onclick=”nativeAdd()”>click</button> <script
type=’text/javascript’> function nativeAdd() { const result =
Module.ccall(‘add’, ‘number’, [‘number’, ‘number’], [2, 3]);
alert(result); } </script>

1
2
3
4
5
6
7
  <button onclick="nativeAdd()">click</button>
  <script type=’text/javascript’>
    function nativeAdd() {
      const result = Module.ccall(‘add’, ‘number’, [‘number’, ‘number’], [2, 3]);
      alert(result);
    }
  </script>

然则,当您点击button的时候,报错:

JavaScript

Assertion failed: the runtime was exited (use NO_EXIT_RUNTIME to keep
it alive after main() exits)

1
Assertion failed: the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)

能够经过在main()中添加emscripten_exit_with_live_runtime()解决:

JavaScript

#include <stdio.h> #include <emscripten.h> int
EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a + b; } int main() {
printf(“a + b: %d”, add(1, 2)); emscripten_exit_with_live_runtime();
return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <emscripten.h>
 
int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
  return a + b;
}
 
int main() {
  printf("a + b: %d", add(1, 2));
  emscripten_exit_with_live_runtime();
  return 0;
}

恐怕也得以直接在命令行中添加-s NO_EXIT_RUNTIME=1来解决,

JavaScript

emcc add2.c -o add2.js -s NO_EXIT_RUNTIME=1

1
emcc add2.c -o add2.js -s NO_EXIT_RUNTIME=1

可是会报1个警示:

JavaScript

exit(0) implicitly called by end of main(), but noExitRuntime, so not
exiting the runtime (you can use emscripten_force_exit, if you want to
force a true shutdown)exit(0) implicitly called by end of main(), but
noExitRuntime, so not exiting the runtime (you can use
emscripten_force_exit, if you want to force a true shutdown)

1
exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)

为此提议利用第3种办法。

上述变动的代码都是asm.js,只需求在编译参数中添加-s WASM=1中就能够转移wasm,然后使用方法都如出一辙。

typedef struct Array
{
    int dim;
    int *ptr;
    int *bounds;
    int *base_add;
}Array;

//gsoap ns service name: SmsWBS
//gsoap ns service style: rpc
//gsoap ns service
namespace: http://192.168.2.161:8000/SmsWBS.wsdl
//gsoap ns service
location: http://192.168.2.161:8000
//gsoap ns service encoding: encoded
//gsoap ns schema namespace: urn:SmsWBS

int main()
{
char sum;
int operator1 = 4874;
//4874 = 0000 0000,0000 0000,0001 0011,0000 1010 hexadecimal 00 00 13
0A
sum = operator1;
//situation 1 sum = 0000 0000; cut the higher bits:13
//situation 2 sum = 0000 1010; cut the lower bits:0A
printf(“sum = %x\n”,sum);

用asm.js和WebAssembly执行耗费时间划算

前面准备干活都做完了,
以往大家来试一下用C代码来优化前一篇中提过的标题。代码很简短:

JavaScript

// file sum.c #include <stdio.h> // #include
<emscripten.h> long sum(long start, long end) { long total = 0;
for (long i = start; i <= end; i += 3) { total += i; } for (long i =
start; i <= end; i += 3) { total -= i; } return total; } int main() {
printf(“sum(0, 1000000000): %ld”, sum(0, 1000000000)); //
emscripten_exit_with_live_runtime(); return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// file sum.c
#include <stdio.h>
// #include <emscripten.h>
 
long sum(long start, long end) {
  long total = 0;
  for (long i = start; i <= end; i += 3) {
    total += i;
  }
  for (long i = start; i <= end; i += 3) {
    total -= i;
  }
  return total;
}
 
int main() {
  printf("sum(0, 1000000000): %ld", sum(0, 1000000000));
  // emscripten_exit_with_live_runtime();
  return 0;
}

注意用gcc编写翻译的时候供给把跟emscriten有关的两行代码注释掉,不然编写翻译可是。
我们先直接用gcc编译成native code看望代码运营多块吧?

JavaScript

➜ webasm-study gcc sum.c ➜ webasm-study time ./a.out sum(0, 1000000000):
0./a.out 5.70s user 0.02s system 99% cpu 5.746 total ➜ webasm-study gcc
-O1 sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.00s
user 0.00s system 64% cpu 0.003 total ➜ webasm-study gcc -O2 sum.c ➜
webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.00s user 0.00s
system 64% cpu 0.003 total

1
2
3
4
5
6
7
8
9
➜  webasm-study gcc sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  5.70s user 0.02s system 99% cpu 5.746 total
➜  webasm-study gcc -O1 sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  0.00s user 0.00s system 64% cpu 0.003 total
➜  webasm-study gcc -O2 sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  0.00s user 0.00s system 64% cpu 0.003 total

能够见到有没有优化差距依然十分大的,优化过的代码执行时间是3ms!。really?仔细思考,作者for循环了10亿次啊,每一趟for执行大致是一次加法,四次赋值,一次相比,而自我一共做了三回for循环,相当于说至少是100亿次操作,而作者的mac
pro是2.5 GHz Intel Core i7,所以1s应有也就实行25亿次CPU指令操作吧,怎么或许逆天到那种程度,肯定是哪儿错了。想起此前看到的一篇rust测试质量的篇章,说rust间接在编写翻译的时候算出了答案,
然后把结果一贯写到了编写翻译出来的代码里,
不亮堂gcc是或不是也做了近乎的工作。在腾讯网上GCC中-O1 -O2 -O3
优化的法则是什么?那篇小说里,
还真有loop-invariant code
motion(LICM)针对for的优化,所以本人把代码扩张了有些if判断,希望能“糊弄”得了gcc的优化。

JavaScript

#include <stdio.h> // #include <emscripten.h> // long
EMSCRIPTEN_KEEPALIVE sum(long start, long end) { long sum(long start,
long end) { long total = 0; for (long i = start; i <= end; i += 1) {
if (i % 2 == 0 || i % 3 == 1) { total += i; } else if (i % 5 == 0 || i %
7 == 1) { total += i / 2; } } for (long i = start; i <= end; i += 1)
{ if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5 == 0 || i
% 7 == 1) { total -= i / 2; } } return total; } int main() {
printf(“sum(0, 1000000000): %ld”, sum(0, 100000000)); //
emscripten_exit_with_live_runtime(); return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
// #include <emscripten.h>
 
// long EMSCRIPTEN_KEEPALIVE sum(long start, long end) {
long sum(long start, long end) {
  long total = 0;
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total += i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total += i / 2;
    }
  }
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total -= i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total -= i / 2;
    }
  }
  return total;
}
 
int main() {
  printf("sum(0, 1000000000): %ld", sum(0, 100000000));
  // emscripten_exit_with_live_runtime();
  return 0;
}

履行结果大概要正规一些了。

JavaScript

➜ webasm-study gcc -O2 sum.c ➜ webasm-study time ./a.out sum(0,
1000000000): 0./a.out 0.32s user 0.00s system 99% cpu 0.324 total

1
2
3
➜  webasm-study gcc -O2 sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  0.32s user 0.00s system 99% cpu 0.324 total

ok,我们来编写翻译成asm.js了。

JavaScript

#include <stdio.h> #include <emscripten.h> long
EMSCRIPTEN_KEEPALIVE sum(long start, long end) { // long sum(long
start, long end) { long total = 0; for (long i = start; i <= end; i
+= 1) { if (i % 2 == 0 || i % 3 == 1) { total += i; } else if (i % 5 ==
0 || i % 7 == 1) { total += i / 2; } } for (long i = start; i <= end;
i += 1) { if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5
== 0 || i % 7 == 1) { total -= i / 2; } } return total; } int main() {
printf(“sum(0, 1000000000): %ld”, sum(0, 100000000));
emscripten_exit_with_live_runtime(); return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <emscripten.h>
 
long EMSCRIPTEN_KEEPALIVE sum(long start, long end) {
// long sum(long start, long end) {
  long total = 0;
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total += i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total += i / 2;
    }
  }
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total -= i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total -= i / 2;
    }
  }
  return total;
}
 
int main() {
  printf("sum(0, 1000000000): %ld", sum(0, 100000000));
  emscripten_exit_with_live_runtime();
  return 0;
}

执行

JavaScript

emcc sum.c -o sum.html

1
emcc sum.c -o sum.html

然后在sum.html中添加代码“

JavaScript

<button onclick=”nativeSum()”>NativeSum</button> <button
onclick=”jsSumCalc()”>JSSum</button> <script
type=’text/javascript’> function nativeSum() { t1 = Date.now(); const
result = Module.ccall(‘sum’, ‘number’, [‘number’, ‘number’], [0,
100000000]); t2 = Date.now(); console.log(`result: ${result}, cost
time: ${t2 – t1}`); } </script> <script
type=’text/javascript’> function jsSum(start, end) { let total = 0;
for (let i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1)
{ total += i; } else if (i % 5 == 0 || i % 7 == 1) { total += i / 2; } }
for (let i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1)
{ total -= i; } else if (i % 5 == 0 || i % 7 == 1) { total -= i / 2; } }
return total; } function jsSumCalc() { const N = 100000000;// 总次数1亿
t1 = Date.now(); result = jsSum(0, N); t2 = Date.now();
console.log(`result: ${result}, cost time: ${t2 – t1}`); }
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<button onclick="nativeSum()">NativeSum</button>
  <button onclick="jsSumCalc()">JSSum</button>
  <script type=’text/javascript’>
    function nativeSum() {
      t1 = Date.now();
      const result = Module.ccall(‘sum’, ‘number’, [‘number’, ‘number’], [0, 100000000]);
      t2 = Date.now();
      console.log(`result: ${result}, cost time: ${t2 – t1}`);
    }
  </script>
  <script type=’text/javascript’>
    function jsSum(start, end) {
      let total = 0;
      for (let i = start; i <= end; i += 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total += i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total += i / 2;
        }
      }
      for (let i = start; i <= end; i += 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total -= i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total -= i / 2;
        }
      }
 
      return total;
    }
    function jsSumCalc() {
      const N = 100000000;// 总次数1亿
      t1 = Date.now();
      result = jsSum(0, N);
      t2 = Date.now();
      console.log(`result: ${result}, cost time: ${t2 – t1}`);
    }
  </script>

除此以外,大家修改成编写翻译成WebAssembly看看效果啊?

JavaScript

emcc sum.c -o sum.js -s WASM=1

1
emcc sum.c -o sum.js -s WASM=1
Browser webassembly asm.js js
Chrome61 1300ms 600ms 3300ms
Firefox55 600ms 800ms 700ms
Safari9.1 不支持 2800ms 因不支持ES6我懒得改写没测试

倍感Firefox有点不创立啊,
暗中认可的JS太强了呢。然后觉得webassembly也没有专门强啊,突然意识emcc编写翻译的时候从不点名牌产品优品化增选-O2。再来3回:“

JavaScript

emcc -O2 sum.c -o sum.js # for asm.js emcc -O2 sum.c -o sum.js -s
WASM=1 # for webassembly

1
2
emcc -O2 sum.c -o sum.js # for asm.js
emcc -O2 sum.c -o sum.js -s WASM=1 # for webassembly
Browser webassembly -O2 asm.js -O2 js
Chrome61 1300ms 600ms 3300ms
Firefox55 650ms 630ms 700ms

甚至没什么变化,
救经引足。号称asm.js能够达到native的一半进程么,那么些倒是好像达到了。但是二〇一九年Compiling
for the Web with WebAssembly (Google I/O
‘17)里说WebAssembly是1.2x slower than native code,感觉不对头呢。asm.js还有一个利益是,它正是js,所以正是浏览器不支持,也能算作分歧的js执行,只是没有加快效果。当然WebAssembly遭受各大厂商一致强调,作为2个新的规范,肯定前景会更好,期待会有更好的显现。

int array_init(Array *a, int dim, …);
int array_set_value(Array *a, int value, …);
int array_print_line(Array *a);
int array_get_value(Array *a, …);
void array_destory(Array *a);

int ns__add(int num1, int num2, int *sum);
其三只文件必要小心的是,前边的 //
部分是有含义的,能够在地方修改,借使完全去掉,将会导致变化的中等文件不相同,因而会滋生要修改Makefile文件                                           

return EXIT_SUCCESS;
}

Rust

理所当然还想写Rust编写翻译成WebAssembly的,可是感觉本文已经太长了,
中期再写倘诺结合Rust做WebAssembly吧。

焦躁的能够先看看那两篇

  • Compiling to the web with Rust and
    emscripten
  • Rust ⇋
    JavaScript

int main(int argc, char *argv[])
{
    Array a;
    int i = 0;
    int j;
    int total = 1;
    array_init(&a, 2, 4, 6);
   
    for(; i < 4; i++)
    {
        for(j = 0; j < 6; j++)
        {
            array_set_value(&a, total++, i, j);
        }
    }

(2)Makefile文件:

如果赋值之后,将保存高位字节,废弃低位字节,将打字与印刷出13H;相反,如若保留低位字节,遗弃低位字节,控制台将会打字与印刷出
0A;

Refers

  • 1 赞 收藏
    评论

金沙澳门官网 3

    array_print_line(&a);
    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 6; j++)
        {
            printf(“%-7d”,array_get_value(&a,  i, j));
        }
        printf(“\n”);
    }
    array_destory(&a);
}

相比较主要,要是头文件中的 // 部分有涂改,要反省是不是要修改Makefile文件

下边编写翻译运维结果为:

int array_init(Array * a, int dim, …)
{
    if(1 > dim || 8 < dim)
        return -1;
    a->dim = dim;

GSOAP_ROOT=/usr/local/gSOAP
WSNAME0=soap
WSNAME=SmsWBS
CC=g++ -g -DWITH_NONAMESPACES
INCLUDE=-I $(GSOAP_ROOT)/include
SERVER_OBJS=$(WSNAME0)C.o $(WSNAME0)Server.o stdsoap2.o
CLIENT_OBJS=$(GSOAP_ROOT)/env/envC.o $(WSNAME0)ClientLib.o
stdsoap2.o
ALL_OBJS=${WSNAME}server.o $(WSNAME0)C.o $(WSNAME0)Server.o
${WSNAME}test.o $(WSNAME0)ClientLib.o
#GSOAP_SRC=/usr/local/gsoap-2.7/gsoap

[html]
[[email protected]
program]# vi addoverflowDemo.c 
[[email protected]
program]# gcc -g addoverflowDemo.c -o addoverflowDemo 
[[email protected]
program]# ./addoverflowDemo  
sum = a 

    va_list ap;
    int i;
    long total = 1;

all:server

[[email protected]
program]# vi addoverflowDemo.c
[[email protected]
program]# gcc -g addoverflowDemo.c -o addoverflowDemo
[[email protected]
program]# ./addoverflowDemo
sum = a

    a->bounds = (int *)malloc(dim * sizeof(int));
   
    va_start(ap, dim);
    for(i = 0; i < dim; i++)
    {
        a->bounds[i] = va_arg(ap, int);
        total *= a->bounds[i];
    }
    va_end(ap);

${WSNAME}.wsdl:${WSNAME}.h
        $(GSOAP_ROOT)/bin/soapcpp2 -c $(GSOAP_ROOT)/import ${WSNAME}.h

GCC下输出为a,表达源程序是保留了不如字节,放弃了高位字节。

    a->ptr = (int *) malloc(total * sizeof(int));

stdsoap2.o:$(GSOAP_ROOT)/src/stdsoap2.c
        $(CC) -c $? $(INCLUDE)

方法二:

    a->base_add = (int *) malloc(dim * sizeof(int));
    a->base_add[dim -1] = 1;
    i = dim -2;
    for(; i >= 0; i–)
    {
        a->base_add[i] = a->base_add[i+1] *
a->bounds[i+1];
    }

$(ALL_OBJS):%.o:%.c
        $(CC) -c $? $(INCLUDE)

别的,通过判断此机器的cpu的大小端方式,也得以判定它的输入,具体方法如下:

    return 0;
}

server:Makefile ${WSNAME}.wsdl ${WSNAME}server.o $(SERVER_OBJS)
        $(CC) ${WSNAME}server.o $(SERVER_OBJS) -o ${WSNAME}server

比喻如下,判断机器的大小端格局:

#define FREE(x) if(NULL != (x)) free(x)

client:Makefile ${WSNAME}.wsdl ${WSNAME}test.c $(ALL_OBJS) stdsoap2.o
        $(CC) ${WSNAME}test.o $(CLIENT_OBJS) -o ${WSNAME}test

判断代码:

void array_destory(Array *a)
{
    FREE(a->ptr);
    FREE(a->bounds);
    FREE(a->base_add);
}

clean:
        rm -f *.o *.xml *.a *.wsdl *.nsmap $(WSNAME0)H.h
$(WSNAME0)C.c $(WSNAME0)Server.c $(WSNAME0)Client.c $(WSNAME0)Stub.*
$(WSNAME)$(WSNAME)Proxy.* $(WSNAME)$(WSNAME)Object.*
$(WSNAME0)ServerLib.c $(WSNAME0)ClientLib.c $(WSNAME)server ns.xsd
$(WSNAME)test

[html]
#include <stdio.h> 
#include <stdlib.h> 
 
int checkCPU( ); 
int main() 

printf(“little endian: %d\n”,checkCPU()); 
return EXIT_SUCCESS; 

int checkCPU( ) 

    { 
           union w 
           {   
                  int  a; 
                  char b; 
           } c; 
           c.a = 0x12345678; 
           return(c.b ==0x78); 
    } 
}  

int array_get_value(Array *a, …)
{
    va_list va;
    va_start(va, a);
   
    int result = array_get_locate(a, va);
    if(-1 == result) return -1;
    return a->ptr[result];
}

 

#include <stdio.h>
#include <stdlib.h>

int array_print_line(Array *a)
{
    int total = 1;
    int i = 0;
    int line ;
    for(; i < a->dim; i++)
    {
        total *= a->bounds[i];
    }
   
    line = total/a->bounds[0];
    for(i = 0; i < total; i++)
    {
        if(0 == i % line && 0 != i) printf(“\n”);
        printf(“%-7d”, a->ptr[i]);
    }
    printf(“\n”);
    return 0;
}

(3)服务端程序SmsWBSserver.c:

int checkCPU( );
int main()
{
printf(“little endian: %d\n”,checkCPU());
return EXIT_SUCCESS;
}
int checkCPU( )
{
    {
           union w
           { 
                  int  a;
                  char b;
           } c;
           c.a = 0x12345678;
           return(c.b ==0x78);
    }
}

int array_get_locate(Array *a, va_list va)
{
    int result = 0;
    int bound;
    int i;
    for(i = 0; i < a->dim; i++)
    {
        bound = va_arg(va, int);
        if(0 > bound || bound > a->bounds[i])
        {
            return -1;
        }
        result += bound * a->base_add[i];
    }
    return result;
}

#include “soapH.h”
#include “SmsWBS.nsmap”

一般来说为源代码解释分析:

int array_set_value(Array *a, int value, …)
{
    if(NULL == a) return -1;
    va_list va;
    va_start(va, value);

int main(int argc, char **argv)
{
        int m, s;               /* master and slave sockets */
        struct soap SmsWBS_soap;

union中定义的是变量公用地址空间,所以整形变量 a和字符型的变量
b的苗子地址是同样的,即一从头存放的岗位是同一的。

    int result = array_get_locate(a, va);
    if( -1 == result) return -1;

        soap_init(&SmsWBS_soap);

a = 0X12345678

    a->ptr[result] = value;
    return 0;
}

        soap_set_namespaces(&SmsWBS_soap, namespaces);

只要要咬定,cpu种类是多方面照旧小端,就得知道
12看成高位字节是存放在在了内部存款和储蓄器的高地址端照旧低地址端,即便高位字节存放在了高地址端,那么 
char(a)只占用1个字节,它的值就应有是空中首地方的值:78,此时称之为小端方式;

 

        if (argc < 2)
        {
                printf(“usage: %s <server_port> \n”,
argv[0]);
                exit(1);
        }
        else
        {
                m = soap_bind(&SmsWBS_soap, NULL, atoi(argv[1]),
100);
                if (m < 0)
                {
                        soap_print_fault(&SmsWBS_soap, stderr);
                        exit(-1);
                }

不过只要char(a)的值是
12,那么就注脚高位字节存放在了低地址端,此时是多方面方式:参考下图:

                fprintf(stderr, “Socket connection successful: master
socket = %d\n”, m);

内部存款和储蓄器地址 小端情势 大端方式
0x8000 78 12
0x8001 56 34
0x8002 34 56
0x8003 12 78

                for (;;)
                {
                        s = soap_accept(&SmsWBS_soap);

如上代码输出结果为:

                        if (s < 0)
                        {
                                soap_print_fault(&SmsWBS_soap,
stderr);
                                exit(-1);
                        }

[html]
[[email protected]
program]# gcc -g checkendianDemo.c -o checkendianDemo 
[[email protected]
program]# ./checkendianDemo  
little endian: 1 

                        fprintf(stderr, “Socket connection successful:
slave socket = %d\n”, s);
                        soap_serve(&SmsWBS_soap);
                        soap_end(&SmsWBS_soap);
                }

[[email protected]
program]# gcc -g checkendianDemo.c -o checkendianDemo
[[email protected]
program]# ./checkendianDemo
little endian: 1

       }

如上二种方法可互相判断。

        return 0;
}

int ns__add(struct soap *add_soap, int num1, int num2, int *sum)
{
        *sum = num1 + num2;
        return 0;
}

 

(4)客户端程序SmsWBStest.c:

#include <stdio.h>
#include <stdlib.h>
#include “soapStub.h”
#include “SmsWBS.nsmap”

int add(const char *server, int num1, int num2, int *sum);

int add(const char *server, int num1, int num2, int *sum)
{
        struct soap SmsWBS_soap;
        int result = 0;

        soap_init(&SmsWBS_soap);
        soap_set_namespaces(&SmsWBS_soap, namespaces);

        soap_call_ns__add(&SmsWBS_soap, server, “”, num1, num2,
sum);

        if(SmsWBS_soap.error)
        {
                printf(“soap error:%d, %s, %s “, SmsWBS_soap.error,
*soap_faultcode(&SmsWBS_soap), *soap_faultstring(&SmsWBS_soap));
                result = SmsWBS_soap.error;
         }

        soap_end(&SmsWBS_soap);
        soap_done(&SmsWBS_soap);

        return result;
}

int main(int argc, char **argv)
{
        int result = -1;
        char* server=”http://localhost:8000″;

        int num1 = 0;
        int num2 = 0;
        int sum = 0;

        if( argc < 3 )
        {
                printf(“usage: %s num1 num2 \n”, argv[0]);
                exit(0);

        }

        num1 = atoi(argv[1]);
        num2 = atoi(argv[2]);

        result = add(server, num1, num2, &sum);
        if (result != 0)
        {
                printf(“soap err, errcode = %d \n”, result);
        }
        else
        {
                printf(“%d + %d = %d \n”, num1, num2, sum);
        }

        return 0;
}

(5)编写翻译和平运动行:

前边都已经准备好了,未来只要求:

make                                     —得到服务端程序SmsWBSserver

make client                            —获得客户端程序SmsWBStest

SmsWBSserver 玖仟             —-运转服务端程序

出来类似上面的显得就象征运转如常

Socket connection successful: master socket = 3

再运营客户端程序:

SmsWBStest 67 78

显示:

67 + 78 = 145

调用Web Service成功

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图