日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

tvm模型部署c++ 分析

發(fā)布時(shí)間:2023/11/28 生活经验 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tvm模型部署c++ 分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

tvm模型部署c++ 分析
tvm c++部署官方教程
https://github.com/apache/tvm/tree/main/apps/howto_deploy
https://tvm.apache.org/docs/how_to/deploy/cpp_deploy.html
官方說(shuō)執(zhí)行run_example.sh腳本就可以完成部署。
使用C++ API部署TVM模塊
提供了一個(gè)關(guān)于如何在apps/howto_deploy中,部署TVM模塊的示例。要運(yùn)行該示例,可以使用以下命令
cd apps/howto_deploy
./run_example.sh
獲取TVM運(yùn)行庫(kù)
唯一需要的是鏈接到目標(biāo)平臺(tái)中的TVM運(yùn)行時(shí)。TVM提供了一個(gè)最低運(yùn)行時(shí)間,根據(jù)使用的模塊數(shù)量,成本大約在300K到600K之間。在大多數(shù)情況下,可以使用libtvm_runtime.com,這是構(gòu)建時(shí)附帶的。
如果發(fā)現(xiàn)很難構(gòu)建libtvm_運(yùn)行時(shí),checkout tvm_runtime_pack.cc。這是一個(gè)提供TVM運(yùn)行時(shí)的示例。可以使用構(gòu)建系統(tǒng)編譯此文件,包含到項(xiàng)目中。
可以checkout應(yīng)用程序,如在iOS、Android和其它平臺(tái)上,使用TVM構(gòu)建的應(yīng)用程序。
動(dòng)態(tài)庫(kù)與系統(tǒng)模塊

TVM提供了兩種使用已編譯庫(kù)的方法。可以checkout prepare_test_libs.py(關(guān)于如何生成庫(kù))和cpp_deploy.cc(關(guān)于如何使用)。
將庫(kù)存儲(chǔ)為共享庫(kù),并將庫(kù)動(dòng)態(tài)加載到項(xiàng)目中。
以系統(tǒng)模塊模式將編譯后的庫(kù)綁定到項(xiàng)目中。
動(dòng)態(tài)加載更靈活,可以動(dòng)態(tài)加載新模塊。系統(tǒng)模塊是一種更靜態(tài)的方法。可以在禁止動(dòng)態(tài)庫(kù)加載的地方使用系統(tǒng)模塊。
c++部署代碼
https://github.com/apache/tvm/blob/main/apps/howto_deploy/cpp_deploy.cc
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* “License”); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/*!* \brief Example code on load and run TVM module.s* \file cpp_deploy.cc*/
#include <dlpack/dlpack.h>
#include <tvm/runtime/module.h>
#include <tvm/runtime/packed_func.h>
#include <tvm/runtime/registry.h>#include <cstdio>void Verify(tvm::runtime::Module mod, std::string fname) {// Get the function from the module.tvm::runtime::PackedFunc f = mod.GetFunction(fname);ICHECK(f != nullptr);// Allocate the DLPack data structures.//// Note that we use TVM runtime API to allocate the DLTensor in this example.// TVM accept DLPack compatible DLTensors, so function can be invoked// as long as we pass correct pointer to DLTensor array.//// For more information please refer to dlpack.// One thing to notice is that DLPack contains alignment requirement for// the data pointer and TVM takes advantage of that.// If you plan to use your customized data container, please// make sure the DLTensor you pass in meet the alignment requirement.//DLTensor* x;DLTensor* y;int ndim = 1;int dtype_code = kDLFloat;int dtype_bits = 32;int dtype_lanes = 1;int device_type = kDLCPU;int device_id = 0;int64_t shape[1] = {10};TVMArrayAlloc(shape, ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &x);TVMArrayAlloc(shape, ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &y);for (int i = 0; i < shape[0]; ++i) {static_cast<float*>(x->data)[i] = i;}// Invoke the function// PackedFunc is a function that can be invoked via positional argument.// The signature of the function is specified in tvm.buildf(x, y);// Print out the outputfor (int i = 0; i < shape[0]; ++i) {ICHECK_EQ(static_cast<float*>(y->data)[i], i + 1.0f);}LOG(INFO) << "Finish verification...";TVMArrayFree(x);TVMArrayFree(y);
}void DeploySingleOp() {// Normally we can directlytvm::runtime::Module mod_dylib = tvm::runtime::Module::LoadFromFile("lib/test_addone_dll.so");LOG(INFO) << "Verify dynamic loading from test_addone_dll.so";Verify(mod_dylib, "addone");// For libraries that are directly packed as system lib and linked together with the app// We can directly use GetSystemLib to get the system wide library.LOG(INFO) << "Verify load function from system lib";tvm::runtime::Module mod_syslib = (*tvm::runtime::Registry::Get("runtime.SystemLib"))();Verify(mod_syslib, "addonesys");
}void DeployGraphExecutor() {LOG(INFO) << "Running graph executor...";// load in the libraryDLDevice dev{kDLCPU, 0};tvm::runtime::Module mod_factory = tvm::runtime::Module::LoadFromFile("lib/test_relay_add.so");// create the graph executor moduletvm::runtime::Module gmod = mod_factory.GetFunction("default")(dev);tvm::runtime::PackedFunc set_input = gmod.GetFunction("set_input");tvm::runtime::PackedFunc get_output = gmod.GetFunction("get_output");tvm::runtime::PackedFunc run = gmod.GetFunction("run");// Use the C++ APItvm::runtime::NDArray x = tvm::runtime::NDArray::Empty({2, 2}, DLDataType{kDLFloat, 32, 1}, dev);tvm::runtime::NDArray y = tvm::runtime::NDArray::Empty({2, 2}, DLDataType{kDLFloat, 32, 1}, dev);for (int i = 0; i < 2; ++i) {for (int j = 0; j < 2; ++j) {static_cast<float*>(x->data)[i * 2 + j] = i * 2 + j;}}// set the right inputset_input("x", x);// run the coderun();// get the outputget_output(0, y);for (int i = 0; i < 2; ++i) {for (int j = 0; j < 2; ++j) {ICHECK_EQ(static_cast<float*>(y->data)[i * 2 + j], i * 2 + j + 1);}}
}int main(void) {DeploySingleOp();DeployGraphExecutor();return 0;
}

Makefile文件
https://github.com/apache/tvm/blob/main/apps/howto_deploy/Makefile

Licensed to the Apache Software Foundation (ASF) under one

# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.# Makefile Example to deploy TVM modules.
TVM_ROOT=$(shell cd ../..; pwd)
DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-corePKG_CFLAGS = -std=c++14 -O2 -fPIC\-I${TVM_ROOT}/include\-I${DMLC_CORE}/include\-I${TVM_ROOT}/3rdparty/dlpack/include\-DDMLC_USE_LOGGING_LIBRARY=\<tvm/runtime/logging.h\>PKG_LDFLAGS = -L${TVM_ROOT}/build -ldl -pthread.PHONY: clean allall: lib/cpp_deploy_pack lib/cpp_deploy_normal# Build rule for all in one TVM package library
lib/libtvm_runtime_pack.o: tvm_runtime_pack.cc@mkdir -p $(@D)$(CXX) -c $(PKG_CFLAGS) -o $@  $^# The code library built by TVM
lib/test_addone_sys.o: prepare_test_libs.py@mkdir -p $(@D)python3 prepare_test_libs.py# Deploy using the all in one TVM package library
lib/cpp_deploy_pack: cpp_deploy.cc lib/test_addone_sys.o lib/libtvm_runtime_pack.o@mkdir -p $(@D)$(CXX) $(PKG_CFLAGS) -o $@  $^ $(PKG_LDFLAGS)# Deploy using pre-built libtvm_runtime.so
lib/cpp_deploy_normal: cpp_deploy.cc lib/test_addone_sys.o@mkdir -p $(@D)$(CXX) $(PKG_CFLAGS) -o $@  $^ -ltvm_runtime $(PKG_LDFLAGS)
clean:

結(jié)合Makefile文件和run_example.sh腳本一起看
腳本先創(chuàng)建lib目錄,然后執(zhí)行sudo make命令,make操作的執(zhí)行要看Makefile文件
make命令會(huì)先在lib文件夾中編譯一個(gè)名為libtvm_runtime_pack.o的靜態(tài)鏈接庫(kù)
然后運(yùn)行prepare_test_lib.py文件生成將模型生成為test_addone_dll.so,test_addone_sys.o和test_relay_add.so三個(gè)庫(kù),給cpp_deploy.cc調(diào)用,生成兩個(gè)可執(zhí)行文件cpp_deploy_pack和cpp_deploy_normal
目標(biāo)是用其它框架寫(xiě)的深度學(xué)習(xí)網(wǎng)絡(luò),通過(guò)tvm轉(zhuǎn)換成so文件,使用c++部署,在gpu上進(jìn)行調(diào)用,下面是cpu上部署的代碼
/*

  • Licensed to the Apache Software Foundation (ASF) under one
  • or more contributor license agreements. See the NOTICE file
  • distributed with this work for additional information
  • regarding copyright ownership. The ASF licenses this file
  • to you under the Apache License, Version 2.0 (the
  • “License”); you may not use this file except in compliance
  • with the License. You may obtain a copy of the License at
  • http://www.apache.org/licenses/LICENSE-2.0
  • Unless required by applicable law or agreed to in writing,
  • software distributed under the License is distributed on an
  • “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  • KIND, either express or implied. See the License for the
  • specific language governing permissions and limitations
  • under the License.
    */

/*!

  • \brief Example code on load and run TVM module.s
  • \file cpp_deploy.cc
    */
    #include <dlpack/dlpack.h>
    #include <tvm/runtime/module.h>
    #include <tvm/runtime/packed_func.h>
    #include <tvm/runtime/registry.h>

#include

#include
#include
#include
using namespace std;

template
Type stringToNum(const string& str)
{
istringstream iss(str);
Type num;
iss >> num;
return num;
}

void DeployGraphRuntime() {

ifstream in("/home/aiteam/tiwang/tvm-tfs-gpu-bkp/data.txt");
//int image[784];
string s;
int image_index=0;
/*
while(getline(in,s))
{
image[i]=stringToNum(s);
++i;
}*/
LOG(INFO) << “Running graph runtime…”;
// load in the library
DLContext ctx{kDLGPU, 0};
tvm::runtime::Module mod_factory = tvm::runtime::Module::LoadFromFile("/home/aiteam/tiwang/tvm-tfs-gpu-bkp/model.so");
// create the graph runtime module
tvm::runtime::Module gmod = mod_factory.GetFunction(“default”)(ctx);
tvm::runtime::PackedFunc set_input = gmod.GetFunction(“set_input”);
tvm::runtime::PackedFunc get_output = gmod.GetFunction(“get_output”);
tvm::runtime::PackedFunc run = gmod.GetFunction(“run”);

// Use the C++ API
tvm::runtime::NDArray x = tvm::runtime::NDArray::Empty({1,784}, DLDataType{kDLFloat, 32, 1}, ctx);
tvm::runtime::NDArray y = tvm::runtime::NDArray::Empty({1, 10}, DLDataType{kDLFloat, 32, 1}, ctx);

while(getline(in,s))
{
static_cast<float*>(x->data)[image_index]=((float)stringToNum(s))/255;
image_index++;
}
// set the right input
set_input(“x”, x);
// run the code
run();
// get the output
get_output(0, y);
for(int i=0;i<10;++i)
{
LOG(INFO)<<static_cast<float*>(y->data)[i];
}
/*
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
ICHECK_EQ(static_cast<float*>(y->data)[i * 2 + j], i * 2 + j + 1);
}
}*/
}

int main(void) {
//DeploySingleOp();
DeployGraphRuntime();
return 0;
}

思路很簡(jiǎn)單就是把數(shù)據(jù)讀進(jìn)來(lái),set_input,run然后get_output,修改了將target修改成cuda后并不能成功在gpu上運(yùn)行,會(huì)出現(xiàn)core dump的問(wèn)題
原因是想要讓模型在gpu上運(yùn)行,需要在gpu上開(kāi)辟內(nèi)存,然后將數(shù)據(jù)拷貝到gpu上運(yùn)行,這個(gè)代碼沒(méi)有這些操作所以運(yùn)行時(shí)會(huì)導(dǎo)致core崩潰。
下面是tvm c++部署調(diào)用gpu的完整過(guò)程,深度學(xué)習(xí)模型使用keras寫(xiě)的mnist手寫(xiě)體識(shí)別網(wǎng)絡(luò),保存成了pb格式,模型代碼就不放了,這里直接讀取pb文件進(jìn)行轉(zhuǎn)化,模型輸入是(1,784),輸出是(1,10)
導(dǎo)入頭文件
import tvm
from tvm import te
from tvm import relay

os and numpy

import numpy as np
import os.path

Tensorflow imports

import tensorflow as tf

try:
tf_compat_v1 = tf.compat.v1
except ImportError:
tf_compat_v1 = tf

Tensorflow utility functions

import tvm.relay.testing.tf as tf_testing
from tvm.contrib import graph_runtime

參數(shù)設(shè)置
#cpu
#target = “l(fā)lvm”
#target_host = “l(fā)lvm”
#layout = None
#ctx = tvm.cpu(0)

#gpu
target = “cuda”
target_host = ‘llvm’
layout = “NCHW”
ctx = tvm.gpu(0)
處理數(shù)據(jù)
from tensorflow.python.keras.datasets import mnist
from tensorflow.python.keras.utils import np_utils

(x_train,y_train),(x_test,y_test)=mnist.load_data()
x_test1=x_test.reshape(x_test.shape[0],x_test.shape[1]*x_test.shape[2])

print(x_train.shape,x_test.shape)
print(y_train.shape,y_test.shape)
x_train=x_train.reshape(x_train.shape[0],x_train.shape[1]*x_train.shape[2])
x_test=x_test.reshape(x_test.shape[0],x_test.shape[1]*x_test.shape[2])
x_train=x_train/255
x_test=x_test/255
y_train=np_utils.to_categorical(y_train)
y_test=np_utils.to_categorical(y_test)
print(x_train.shape,x_test.shape)
print(y_train.shape,y_test.shape)

with open(“data.txt”,‘w’) as wf:
for i in range(784):
wf.write(str(x_test1[12][i]))
wf.write(’\n’)
讀取模型
with tf_compat_v1.gfile.GFile(’./frozen_models/simple_frozen_graph.pb’, “rb”) as f:
graph_def = tf_compat_v1.GraphDef()
graph_def.ParseFromString(f.read())
graph = tf.import_graph_def(graph_def, name="")
# Call the utility to import the graph definition into default graph.
graph_def = tf_testing.ProcessGraphDefParam(graph_def)
# Add shapes to the graph.

config = tf.compat.v1.ConfigProto(allow_soft_placement=True)
with tf_compat_v1.Session() as sess:graph_def = tf_testing.AddShapesToGraphDef(sess, "Identity")

tensor_name_list = [tensor.name for tensor in tf.compat.v1.get_default_graph().as_graph_def().node]
for tensor_name in tensor_name_list:
print(tensor_name,’\n’)
構(gòu)建
shape_dict = {“x”: x_train[0:1].shape}
print(shape_dict)
dtype_dict = {“x”: “uint8”}
mod, params = relay.frontend.from_tensorflow(graph_def, layout=layout, shape=shape_dict)

print(“Tensorflow protobuf imported to relay frontend.”)

編譯成tvm模型
with tvm.transform.PassContext(opt_level=3):
lib = relay.build(mod, target=target, target_host=target_host, params=params)

測(cè)試一下tvm模型能不能用
from tvm.contrib import graph_runtime

tt=np.zeros([1,784])
i=0
file=open(“data.txt”)
while 1:
line=file.readline()
if not line:
break
tt[0][i]=int(line)
i+=1
file.close()

dtype = “float32”
m = graph_runtime.GraphModule(lib"default")

set inputs

m.set_input(“x”, tvm.nd.array(tt.astype(dtype)))

execute

m.run()

get outputs

tvm_output = m.get_output(0, tvm.nd.empty(((1, 10)), “float32”))
print(tvm_output.shape,tvm_output)

保存模型
from tvm.contrib import utils
temp=utils.tempdir()
path_lib=temp.relpath("/home/aiteam/test_code/model.so")
print(path_lib)
lib.export_library(path_lib)
print(temp.listdir())
然后進(jìn)入到tvm/apps/howto_deploy目錄,修改tvm_runtime_pack.cc文件,加上頭文件
#include “…/…/src/runtime/cuda/cuda_device_api.cc”
#include “…/…/src/runtime/cuda/cuda_module.cc”
然后再寫(xiě)一個(gè)cc文件存放自己的部署代碼,修改Makefile文件進(jìn)行編譯
文件名是cpp_deploy_bkp.cc
修改后的Makefile文件

Licensed to the Apache Software Foundation (ASF) under one

or more contributor license agreements. See the NOTICE file

distributed with this work for additional information

regarding copyright ownership. The ASF licenses this file

to you under the Apache License, Version 2.0 (the

“License”); you may not use this file except in compliance

with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,

software distributed under the License is distributed on an

“AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

KIND, either express or implied. See the License for the

specific language governing permissions and limitations

under the License.

Makefile Example to deploy TVM modules.

TVM_ROOT=(shellcd../..;pwd)DMLCCORE=(shell cd ../..; pwd) DMLC_CORE=(shellcd../..;pwd)DMLCC?ORE={TVM_ROOT}/3rdparty/dmlc-core

PKG_CFLAGS = -std=c++14 -g -fPIC
-IKaTeX parse error: Undefined control sequence: \ at position 19: …M_ROOT}/include\? ? -I{DMLC_CORE}/include
-I${TVM_ROOT}/3rdparty/dlpack/include
-I/usr/local/cuda/include

PKG_LDFLAGS = -L${TVM_ROOT}/build -ldl -pthread -L/usr/local/cuda/lib64 -lcudart -lcuda

.PHONY: clean all
all:lib/libtvm_runtime_pack.o lib/cpp_deploy_pack

#all: lib/cpp_deploy_pack lib/cpp_deploy_normal

Build rule for all in one TVM package library

.PHONY: lib/libtvm_runtime_pack.o
lib/libtvm_runtime_pack.o: tvm_runtime_pack.cc
@mkdir -p $(@D)
$(CXX) -c $(PKG_CFLAGS) -o $@ $^ $(PKG_LDFLAGS)

Deploy using the all in one TVM package library

.PHONY: lib/cpp_deploy_pack
lib/cpp_deploy_pack: cpp_deploy_bkp.cc lib/libtvm_runtime_pack.o
@mkdir -p $(@D)
$(CXX) $(PKG_CFLAGS) -o $@ $^ $(PKG_LDFLAGS)
里面要加上cuda頭文件的位置和動(dòng)態(tài)鏈接庫(kù)的位置
cpp_deploy_bkp.cc
/*

  • Licensed to the Apache Software Foundation (ASF) under one
  • or more contributor license agreements. See the NOTICE file
  • distributed with this work for additional information
  • regarding copyright ownership. The ASF licenses this file
  • to you under the Apache License, Version 2.0 (the
  • “License”); you may not use this file except in compliance
  • with the License. You may obtain a copy of the License at
  • http://www.apache.org/licenses/LICENSE-2.0
  • Unless required by applicable law or agreed to in writing,
  • software distributed under the License is distributed on an
  • “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  • KIND, either express or implied. See the License for the
  • specific language governing permissions and limitations
  • under the License.
    */

/*!

  • \brief Example code on load and run TVM module.s
  • \file cpp_deploy.cc
    */

#include <dlpack/dlpack.h>
#include <tvm/runtime/module.h>
#include <tvm/runtime/packed_func.h>
#include <tvm/runtime/registry.h>

#include

#include
#include
#include
using namespace std;

template
Type stringToNum(const string& str)
{
istringstream iss(str);
Type num;
iss >> num;
return num;
}
void DeployGraphRuntime() {
constexpr int dtype_code= 2U;
constexpr int dtype_bits=32;
constexpr int dtype_lines=1;
constexpr int device_type= 2;
constexpr int device_id=0;
int ndim=2;
int64_t in_shape[2]={1,784};
int64_t out_shape[2]={1,10};

DLTensor* DLTX=nullptr;
DLTensor* DLTY=nullptr;

TVMArrayAlloc(in_shape,ndim,dtype_code,dtype_bits,dtype_lines,device_type,device_id,&DLTX);
TVMArrayAlloc(out_shape,ndim,dtype_code,dtype_bits,dtype_lines,device_type,device_id,&DLTY);

float img[784];
float rslt[10];

ifstream in("/home/aiteam/tiwang/data.txt");
//int image[784];
string s;
int image_index=0;
/*
while(getline(in,s))
{
image[i]=stringToNum(s);
++i;
}*/
bool enabled = tvm::runtime::RuntimeEnabled(“cuda”);
if (!enabled)
{
LOG(INFO) << “Skip heterogeneous test because cuda is not enabled.”<< “\n”;
return;
}

LOG(INFO) << “Running graph runtime…”;
// load in the library
DLContext ctx{kDLGPU, 0};
tvm::runtime::Module mod_factory = tvm::runtime::Module::LoadFromFile("/home/aiteam/test_code/model.so");
// create the graph runtime module
tvm::runtime::Module gmod = mod_factory.GetFunction(“default”)(ctx);
tvm::runtime::PackedFunc set_input = gmod.GetFunction(“set_input”);
tvm::runtime::PackedFunc get_output = gmod.GetFunction(“get_output”);
tvm::runtime::PackedFunc run = gmod.GetFunction(“run”);

// Use the C++ API
while(getline(in,s))
{
if(image_index%28==0)
printf("\n");
//static_cast<float*>(x->data)[image_index]=((float)stringToNum(s))/255;
img[image_index]=((float)stringToNum(s))/255;

  int a=stringToNum<int>(s);printf("%4d",a);image_index++;

}
TVMArrayCopyFromBytes(DLTX,&img[0],image_indexsizeof(float));
// set the right input
set_input(“x”, DLTX);
// run the code
run();
// get the output
get_output(0, DLTY);
TVMArrayCopyToBytes(DLTY,&rslt[0],10
sizeof(float));

for(int i=0;i<10;++i)
{
LOG(INFO)<<rslt[i];
//LOG(INFO)<<static_cast<float*>(y->data)[i];
}
}

int main(void) {
//DeploySingleOp();
DeployGraphRuntime();
return 0;
}
相比于之前cpu部署的代碼,gpu部署多了一個(gè)拷貝張量的過(guò)程
參照
https://discuss.tvm.apache.org/t/deploy-nnvm-module-using-c-on-gpu-using-opencl-target/229
最終結(jié)果
首先在tvm/apps/howto_deplpy目錄下執(zhí)行sudo make

編譯通過(guò),運(yùn)行可執(zhí)行文件 ./lib/cpp_deploy_pack

參考鏈接:
https://www.cnblogs.com/wangtianning1223/p/14662970.html
https://github.com/apache/tvm/tree/main/apps/howto_deploy
https://discuss.tvm.apache.org/t/deploy-nnvm-module-using-c-on-gpu-using-opencl-target/229/17
https://discuss.tvm.apache.org/t/performance-tvm-pytorch-bert-on-cpu/10200/10
[Performance] TVM - pytorch BERT on CPU

@masahi I add ONNX for the experiments in the following and it seems using ONNX-runtime can get the best performance no matter the sequence length is (without tuning). I use ONNX-runtime with GraphOptimizationLevel.ORT_ENABLE_ALL showing in this link 1. Besides, I plot the IR graph for ONNX, which is quite complicated.
Experiment 1 - Different Target

image1170×432 15.7 KB

Experiment 3 - Different Length

image1632×432 18.1 KB

? ONNX IR Graph: drive link
Also, I have some questions about AutoSchedule tuning.
? Q1: @merrymercy I was confused that when I use AutoSchedule to tune TVM, can I use target like llvm -libs=cblas or I should use only llvm. I found this will give different tasks to tune.
? Q2: @comaniac I think MXNet IR is more friendly than Pytorch IR for AutoSchedule tuning. I set the same parameters for tuning but Pytorch cannot get the results as MXNet (16ms for seq_len=128) The following are their tuning tasks and it seems quite different due to different IR graph. I still work on where the problem comes from, TVM front-end or original code implementation. But I think maybe TVM will have some transforms to generate similar IR graph even if from different framework.
o 1st difference: MXNet will use nn.bias_add() and Pytorch will use relay.add(), which cause the tuning tasks not include this operation. (task 0,1,2,6)
o 2nd difference: Their attention softmax operation have different shape, but I think this doesn’t cause too much latency difference (task 4)

Tasks for Pytorch AutoSchedule Tuning (Target = llvm)

========== Task 0 (workload key: [“61f56dfd63fda28bc8bcf85739c8e9e3”, 128, 3072, 768, 3072, 128, 768]) ==========
placeholder = PLACEHOLDER [128, 3072]
placeholder = PLACEHOLDER [768, 3072]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])

========== Task 1 (workload key: [“61f56dfd63fda28bc8bcf85739c8e9e3”, 128, 768, 3072, 768, 128, 3072]) ==========
placeholder = PLACEHOLDER [128, 768]
placeholder = PLACEHOLDER [3072, 768]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])

========== Task 2 (workload key: [“61f56dfd63fda28bc8bcf85739c8e9e3”, 128, 768, 768, 768, 128, 768]) ==========
placeholder = PLACEHOLDER [128, 768]
placeholder = PLACEHOLDER [768, 768]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])

========== Task 3 (workload key: [“d2a28fdf41e83222456f5a6e5bf8a24a”, 12, 128, 128, 12, 64, 128, 12, 128, 64]) ==========
placeholder = PLACEHOLDER [12, 128, 128]
placeholder = PLACEHOLDER [12, 64, 128]
compute(b, i, j) += (placeholder[b, i, k]*placeholder[b, j, k])

========== Task 4 (workload key: [“868c2771b1610bdac0ac73167691f4eb”, 1, 12, 128, 128, 1, 12, 128, 128]) ==========
placeholder = PLACEHOLDER [1, 12, 128, 128]
T_softmax_maxelem(i0, i1, i2) max= placeholder[i0, i1, i2, k]
T_softmax_delta(i0, i1, i2, i3) = (placeholder[i0, i1, i2, i3] - T_softmax_maxelem[i0, i1, i2])
T_fast_exp(ax0, ax1, ax2, ax3) = max((tir.reinterpret(tir.shift_left(int32((tir.floor(((max(min(T_softmax_delta[ax0, ax1, ax2, a …(OMITTED)… max_delta[ax0, ax1, ax2, ax3], 88.3763f), -88.3763f)*1.4427f) + 0.5f))*0.693147f))) + 1f)), T_softmax_delta[ax0, ax1, ax2, ax3])
T_softmax_expsum(i0, i1, i2) += T_fast_exp[i0, i1, i2, k]
T_softmax_norm(i0, i1, i2, i3) = (T_fast_exp[i0, i1, i2, i3]/T_softmax_expsum[i0, i1, i2])

========== Task 5 (workload key: [“d2a28fdf41e83222456f5a6e5bf8a24a”, 12, 128, 64, 12, 128, 64, 12, 128, 128]) ==========
placeholder = PLACEHOLDER [12, 128, 64]
placeholder = PLACEHOLDER [12, 128, 64]
compute(b, i, j) += (placeholder[b, i, k]*placeholder[b, j, k])

========== Task 6 (workload key: [“61f56dfd63fda28bc8bcf85739c8e9e3”, 128, 768, 2304, 768, 128, 2304]) ==========
placeholder = PLACEHOLDER [128, 768]
placeholder = PLACEHOLDER [2304, 768]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])

========== Task 7 (workload key: [“2dde9ffcbf97381c0f0307643e09dac5”, 1, 128, 768, 1, 128, 1]) ==========
placeholder = PLACEHOLDER [1, 128, 768]
placeholder_red(ax0, ax1, ax2) += placeholder[ax0, ax1, k2]
T_divide(ax0, ax1, ax2) = (placeholder_red[ax0, ax1, ax2]/768f)

========== Task 8 (workload key: [“dde89265d3f1a59075cee648386eac1e”, 1, 128, 768, 1, 128, 1, 1, 128, 1]) ==========
placeholder = PLACEHOLDER [1, 128, 768]
placeholder = PLACEHOLDER [1, 128, 1]
T_subtract(ax0, ax1, ax2) = (placeholder[ax0, ax1, ax2] - placeholder[ax0, ax1, 0])
T_multiply(ax0, ax1, ax2) = (T_subtract[ax0, ax1, ax2]*T_subtract[ax0, ax1, ax2])
T_multiply_red(ax0, ax1, ax2) += T_multiply[ax0, ax1, k2]
T_divide(ax0, ax1, ax2) = (T_multiply_red[ax0, ax1, ax2]/768f)

========== Task 9 (workload key: [“9e3bd222d4f8d250aeadf2fef0b15f2b”, 1, 768, 768, 768, 768, 1, 768]) ==========
placeholder = PLACEHOLDER [1, 768]
placeholder = PLACEHOLDER [768, 768]
T_dense(i, j) += (placeholder[i, k]placeholder[j, k])
placeholder = PLACEHOLDER [768]
T_add(ax0, ax1) = (T_dense[ax0, ax1] + placeholder[ax1])
T_minimum(ax0, ax1) = min(T_add[ax0, ax1], 9f)
T_maximum(ax0, ax1) = max(T_minimum[ax0, ax1], -9f)
T_fast_tanh(ax0, ax1) = ((T_maximum[ax0, ax1]
(((T_maximum[ax0, ax1]T_maximum[ax0, ax1])(((T_maximum[ax0, ax1]*T_maximum[ax0, …(OMITTED)… T_maximum[ax0, ax1])(((T_maximum[ax0, ax1]*T_maximum[ax0, ax1])*1.19826e-06f) + 0.000118535f)) + 0.00226843f)) + 0.00489353f))

Tasks for MXNet AutoSchedule Tuning (Target = llvm)

========== Task 0 (workload key: [“9847f8cc0b305137f49f2c5c0c8ab25d”, 128, 3072, 768, 3072, 768, 128, 768]) ==========
placeholder = PLACEHOLDER [128, 3072]
placeholder = PLACEHOLDER [768, 3072]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])
placeholder = PLACEHOLDER [768]
T_add(ax0, ax1) = (T_dense[ax0, ax1] + placeholder[ax1])

========== Task 1 (workload key: [“9847f8cc0b305137f49f2c5c0c8ab25d”, 128, 768, 3072, 768, 3072, 128, 3072]) ==========
placeholder = PLACEHOLDER [128, 768]
placeholder = PLACEHOLDER [3072, 768]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])
placeholder = PLACEHOLDER [3072]
T_add(ax0, ax1) = (T_dense[ax0, ax1] + placeholder[ax1])

========== Task 2 (workload key: [“9847f8cc0b305137f49f2c5c0c8ab25d”, 128, 768, 768, 768, 768, 128, 768]) ==========
placeholder = PLACEHOLDER [128, 768]
placeholder = PLACEHOLDER [768, 768]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])
placeholder = PLACEHOLDER [768]
T_add(ax0, ax1) = (T_dense[ax0, ax1] + placeholder[ax1])

========== Task 3 (workload key: [“d2a28fdf41e83222456f5a6e5bf8a24a”, 12, 128, 128, 12, 64, 128, 12, 128, 64]) ==========
placeholder = PLACEHOLDER [12, 128, 128]
placeholder = PLACEHOLDER [12, 64, 128]
compute(b, i, j) += (placeholder[b, i, k]*placeholder[b, j, k])

========== Task 4 (workload key: [“4b5e216f8244b4e8f7b6543c4a9087e5”, 1536, 128, 1536, 128]) ==========
placeholder = PLACEHOLDER [1536, 128]
T_softmax_maxelem(i0) max= placeholder[i0, k]
T_softmax_delta(i0, i1) = (placeholder[i0, i1] - T_softmax_maxelem[i0])
T_fast_exp(ax0, ax1) = max((tir.reinterpret(tir.shift_left(int32((tir.floor(((max(min(T_softmax_delta[ax0, ax1], 88.3763f), -88. …(OMITTED)… oor(((max(min(T_softmax_delta[ax0, ax1], 88.3763f), -88.3763f)*1.4427f) + 0.5f))*0.693147f))) + 1f)), T_softmax_delta[ax0, ax1])
T_softmax_expsum(i0) += T_fast_exp[i0, k]
T_softmax_norm(i0, i1) = (T_fast_exp[i0, i1]/T_softmax_expsum[i0])

========== Task 5 (workload key: [“d2a28fdf41e83222456f5a6e5bf8a24a”, 12, 128, 64, 12, 128, 64, 12, 128, 128]) ==========
placeholder = PLACEHOLDER [12, 128, 64]
placeholder = PLACEHOLDER [12, 128, 64]
compute(b, i, j) += (placeholder[b, i, k]*placeholder[b, j, k])

========== Task 6 (workload key: [“9847f8cc0b305137f49f2c5c0c8ab25d”, 128, 768, 2304, 768, 2304, 128, 2304]) ==========
placeholder = PLACEHOLDER [128, 768]
placeholder = PLACEHOLDER [2304, 768]
T_dense(i, j) += (placeholder[i, k]*placeholder[j, k])
placeholder = PLACEHOLDER [2304]
T_add(ax0, ax1) = (T_dense[ax0, ax1] + placeholder[ax1])

========== Task 7 (workload key: [“2dde9ffcbf97381c0f0307643e09dac5”, 128, 1, 768, 128, 1, 1]) ==========
placeholder = PLACEHOLDER [128, 1, 768]
placeholder_red(ax0, ax1, ax2) += placeholder[ax0, ax1, k2]
T_divide(ax0, ax1, ax2) = (placeholder_red[ax0, ax1, ax2]/768f)

========== Task 8 (workload key: [“dde89265d3f1a59075cee648386eac1e”, 128, 1, 768, 128, 1, 1, 128, 1, 1]) ==========
placeholder = PLACEHOLDER [128, 1, 768]
placeholder = PLACEHOLDER [128, 1, 1]
T_subtract(ax0, ax1, ax2) = (placeholder[ax0, ax1, ax2] - placeholder[ax0, ax1, 0])
T_multiply(ax0, ax1, ax2) = (T_subtract[ax0, ax1, ax2]*T_subtract[ax0, ax1, ax2])
T_multiply_red(ax0, ax1, ax2) += T_multiply[ax0, ax1, k2]
T_divide(ax0, ax1, ax2) = (T_multiply_red[ax0, ax1, ax2]/768f)

========== Task 9 (workload key: [“9e3bd222d4f8d250aeadf2fef0b15f2b”, 1, 768, 768, 768, 768, 1, 768]) ==========
placeholder = PLACEHOLDER [1, 768]
placeholder = PLACEHOLDER [768, 768]
T_dense(i, j) += (placeholder[i, k]placeholder[j, k])
placeholder = PLACEHOLDER [768]
T_add(ax0, ax1) = (T_dense[ax0, ax1] + placeholder[ax1])
T_minimum(ax0, ax1) = min(T_add[ax0, ax1], 9f)
T_maximum(ax0, ax1) = max(T_minimum[ax0, ax1], -9f)
T_fast_tanh(ax0, ax1) = ((T_maximum[ax0, ax1]
(((T_maximum[ax0, ax1]T_maximum[ax0, ax1])(((T_maximum[ax0, ax1]*T_maximum[ax0, …(OMITTED)… T_maximum[ax0, ax1])(((T_maximum[ax0, ax1]*T_maximum[ax0, ax1])*1.19826e-06f) + 0.000118535f)) + 0.00226843f)) + 0.00489353f))
Sorry for my lots of questions. I’ll do my best to do more experiments and figure out the reasons why Pytorch AutoSchedule not working as MXNet and why TVM is not working as expected when sequence length increasing.
Reply
Thanks for the plentiful information.
For Q1, when you extract tasks with llvm -mcpu=skylake-avx512 -libs=cblas, some operators (i.e., dense) will be offloaded to cblas. It means those operators won’t be compiled by the TVM codegen, so AutoScheduler won’t see and tune them.
For Q2, the two differences you pointed out seem not really impactful. Maybe you can try to use debugger to compare the latency breakdown between two models: Debugger — tvm 0.8.dev0 documentation 4
Reply
@comaniac I follow your instructions to use debugger and compare the latency in the following IR graphs (latency > 100us with orange color). And I find maybe some operations are hard to tune, such as fused_nn_contrib_dense_pack. All my experiments are done with opt_level=3, required_pass=[“FastMath”]
Experiment 1 - Compare BERT on MXNet (68.4ms) and Pytorch (122.9ms)
? MXNet Debug IR Graph: drive link
? Pytorch Debug IR Graph: drive link 3
? From the above graphs, we can find MXNet use fused_nn_contrib_dense_pack_add while Pytorch use fused_nn_contrib_dense_pack operation. This is happened for all FC layers (4 in one transformer block) and I use the latency of first block as example.
o FC for Query, Key, and Value (M: 503us, P: 1314us)
o FC after self-attention (M: 202us, P: 651us)
o FC after layer normalization (M: 798us, P: 2578us)
o FC after GELU (M: 786us, P: 2572us)

image1043×480 60 KB

Experiment 2 - Compare BERT on MXNet (68.4ms) and MXNet-tune (autoschedule) (15.4ms)
? MXNet Debug IR Graph: drive link
? MXNet-tune Debug IR Graph: drive link
? From the above graphs, it is easy to find we can reduce most of dense and batch_matmul operations’ latency. I take the first transformer block as example.
o FC for Query, Key, and Value (M: 503us, M-tune: 229us)
o FC after self-attention (M: 202us, M-tune: 99us)
o FC after layer normalization (M: 798us, M-tune: 292us)
o FC after GELU (M: 786us, M-tune: 367us)
o batch_matmul for Quert and Key (M: 1828us, M-tune:41us)
o batch_matmul for Attention and Value (M: 1312us, M-tune:29us)
Experiment 3 - Compare BERT on Pytorch (122.9ms) and Pytorch-tune (autoschedule) (64.2ms)
? Pytorch Debug IR Graph: drive link 3
? Pytorch-tune Debug IR Graph: drive link 1
? From the above graphs, we can find we only reduce the latency of batch_matmul but not dense operation. I take the first transformer block as example.
o FC for Query, Key, and Value (P: 1314us, P-tune: 1276us)
o FC after self-attention (P: 651us, P-tune: 403us)
o FC after layer normalization (P: 2578us, P-tune: 1779us)
o FC after GELU (P: 2572us, P-tune: 1684us)
o batch_matmul for Quert and Key (P: 1624us, P-tune: 78us)
o batch_matmul for Attention and Value (P: 1265us, P-tune: 70us)
Therefore, I suspect the problem is come from the fused_nn_contrib_dense_pack operation, but I don’t know why this is slower than fused_nn_contrib_dense_pack_add. Even the latter has additional add operation for adding bias. If you want the whole debug files (json and logs), I provide in this drive link 1.
Reply
@comaniac I change the TVM version with commit id: 91e07e1f3a7 (Feb. 5, 2021) which is the same as this repo 1. And the problem is solved because we will use fused_nn_batch_matmul for all FC (dense) layers rather than fused_nn_contrib_dense_pack. I think the problem is coming from this PR 3 you provided, which also causes I cannot use -libs=mkl. I have the debug IR graphs in the following and now Pytorch can speed up from Pytorch script 26.63ms to 17.36ms after tuning with autoschedule.
? Pytorch Debug IR Graph: drive link 2
? Pytorch-tune Debug IR Graph: drive link 1
2 Replies
1
Reply
Hmm I don’t that PR is the root cause of using batch_matmul in BERT model tho. It might be due to this PR that uses dense instead of batch_matmul when the input shape is 2D and 3D:
github.com/apache/tvm 6
Fix PyTorch matmul conversion when given (2-dim, N-dim) input pair 6
apache:main ← yuchaoli:main
opened Apr 14, 2021
This PR change the matmul conversion in PyTorch when given (2-dim, N-dim) input … 6
Reply
There’s a known issue that TVM’s dense op and batch_matmul op with Y = X * W^T does have bad performance in some models.
There’re several matmul & batch_matmul ops in bert that takes data tensor as both input and weight(exp. those in multi-head attentions) rather than use const parameter as weight. In such situation, we would see some explicit transpose inserted when the model are imported from TensorFlow or Pytorch(they use X * W for matmul by default). For the MXNet, as far as I know, it uses X * W^T by default.
The PR you found looks like creating a special schedule for dense + transpose, I’m not sure if that’s the key of the performance improving you got because it is written for AutoTVM and AutoScheduler will never use these manual schedule. You can have a more detailed analyse among those dense/batch_matmul ops’ layout and shape.
I would agree with @comaniac that the miss conversion from dense to batch_matmul caused some waste of computation before.
Reply
3 MONTHS LATER
will auto-schedule work in case of “l(fā)lvm -libs-cblas”? e.g. a network may contain matmul ops(leverage cblas) and other ops(leverage auto-schedule to get performance)?
Deploy NNVM module using C++ on GPU using OpenCL target

2 MONTHS LATER
Jul '18
@masahi Thanks for the sample .
In your sample code is “tvm_input” the CPU byte array copied to “x” (GPU array) ?
means is TVMArrayCopyFromBytes(destination,source,size) ?
for (int i = 0; i < n_samples; ++i) {
TVMArrayCopyFromBytes(x, &tvm_input[i * in_size], in_size * sizeof(float));
set_input(input_name.c_str(), x);
run();
get_output(0, y);
TVMArrayCopyToBytes(y, &tvm_output[i * out_size], out_size * sizeof(float));
}
Reply
? C++ deploy example: switch to OpenCL7
Jul '18
yes, source is on cpu and x is on gpu. In my code, tvm_input should contain input data coming from your input image, for example.
Reply
Jul '18
@masahi
instead of tvm_input i created a DLTensor ‘z’ of device type = kdCPU , for storing input image .
I did copy byte array as shown below .
https://gist.github.com/rajh619/74538a7b3a7e1b89a2ae89db5ab24054 30
but the i couldnt find the copied bytes in the destination (x->data) .?
Reply
Jul '18
If you already have your data in DLtensor, you should use TVMArrayCopyFromTo.
Reply
Jul '18
@masahi
ok .now i tried with TVMArrayCopyFromTo
TVMArrayCopyFromTo(z, x, nullptr);
the same issue happens , i couldnt find the bytes copied to x->data .
I think x->data should be same as z->data(image data) . please correct me if am wrong ?
Reply
if x is on GPU, you should NEVER touch x->data. You either get segfault or complete junk.
If you want to access x->data, copy x to CPU first.
Reply
@masahi Thanks . got it working . i copied back from GPU to CPU(x->data to k->data) and validated the data.
After executing "run() " , i was able to get output to CPU in two ways :

  1. allocate tvm array to output tensor “y” with devicetype - CPU (1) , then tvm_output(0,y) . y->data contains output . ( i think internally tvm copies the output from device to cpu_host ?)
  2. allocate tvm array to output tensor “y” with devicetype - GPU (4) , tvm_output(0,y) ,then copy bytes from GPU to CPU ->out_vector[] . (similar to your sample code) .
    Out of both which is the right way to extract output ?
    Reply
    The answer is 2.
    See my sample code. The output y is GPU tensor. I copy y to tvm_output, which is on cpu.
    1
    Reply

Hi, @masahi I am still getting segfault even I use your sample 5 code also after allocating memory i am doing memeset to 0
DLTensor* x = nullptr;
DLTensor* y = nullptr;
const int in_ndim = 4;
const int out_ndim = in_ndim;
const int num_slice = 1;
const int num_class = 4;
const int shrink_size[] = { 256, 256 };
const int64_t in_shape[] = { num_slice, 1, shrink_size[0], shrink_size[1] };
const int64_t out_shape[] = { num_slice, num_class, shrink_size[0], shrink_size[1] };
TVMArrayAlloc(in_shape, in_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &x);
TVMArrayAlloc(out_shape, out_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &y);
memset(x->data, 0, 4265265);
it is happing for Cuda and OpenCL for llvm it’s working fine.
Reply
you can’t use memset on GPU memory.
Reply
hi, @masahi still i am not able working still it throws memory error.
void FR_TVM_Deploy::forward(float* imgData)
{
int in_size = (1 * 64 * 64 * 3 * 4);

constexpr int dtype_code = kDLFloat;
constexpr int dtype_bits = 32;
constexpr int dtype_lanes = 1;
constexpr int device_type = kDLCPU;
constexpr int device_id = 0;
constexpr int in_ndim = 4;
const int64_t in_shape[in_ndim] = {1, 64, 64, 3};
//Allocating memeory to DLTensor object
TVMArrayAlloc(in_shape, in_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &input);//
TVMArrayCopyFromBytes(input, imgData, in_size);
//Get globl function module for graph runtime
tvm::runtime::Module* mod = (tvm::runtime::Module*)handle;
// get the function from the module(set input data)
tvm::runtime::PackedFunc set_input = mod->GetFunction(“set_input”);
set_input(“input”, input);
// get the function from the module(run it)
tvm::runtime::PackedFunc run = mod->GetFunction(“run”);
run();

int out_ndim = 2;
int64_t out_shape[2] = {1, 256};
TVMArrayAlloc(out_shape, out_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &output);
// get the function from the module(get output data)
tvm::runtime::PackedFunc get_output = mod->GetFunction(“get_output”);
get_output(0, output);
size_t out_size = out_shape[0] * out_shape[1];
std::vector tvm_output(out_size, 0);
TVMArrayCopyToBytes(output, &tvm_output[out_size], out_size);

TVMArrayFree(input);
TVMArrayFree(output);
}
when i print the tvm_output vector i am getting all 0’s means output is coming 0, in llvm case i am getting correct output. here i am printing vector tvm_output in loop, is there any othere way to check output?
參考鏈接:
https://www.cnblogs.com/wangtianning1223/p/14662970.html
https://github.com/apache/tvm/tree/main/apps/howto_deploy
https://discuss.tvm.apache.org/t/deploy-nnvm-module-using-c-on-gpu-using-opencl-target/229/17
https://discuss.tvm.apache.org/t/performance-tvm-pytorch-bert-on-cpu/10200/10

總結(jié)

以上是生活随笔為你收集整理的tvm模型部署c++ 分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

日韩电影黄色 | 久久国产精品免费观看 | 午夜精品成人一区二区三区 | 日韩电影在线观看一区二区三区 | 国产精品一区二区久久精品爱微奶 | 毛片美女网站 | a天堂最新版中文在线地址 久久99久久精品国产 | 正在播放 国产精品 | 日韩欧美高清在线 | 久久一区二区三区超碰国产精品 | 91福利免费| 国产精品久久久久久久久婷婷 | 2019中文字幕第一页 | 久久久久久国产精品 | 在线免费观看欧美日韩 | 久久蜜臀一区二区三区av | 五月天综合网站 | 欧美日韩精品在线观看视频 | 国产日韩欧美自拍 | 91免费网址| 中国一级片免费看 | 日韩免费观看视频 | 日韩欧美在线免费 | 天天激情综合 | 亚洲综合日韩在线 | 精品视频久久久 | 国产精品美 | 人人舔人人干 | 91成人在线视频观看 | 国产精品久久久久久吹潮天美传媒 | 免费男女羞羞的视频网站中文字幕 | 激情片av| 日韩欧美在线综合网 | 国产精品久久久久aaaa | av成人亚洲 | 国产亚洲精品久久久久秋 | 国产精品久久99精品毛片三a | 中文字幕在线影院 | 9999精品| 欧美日韩免费在线视频 | 男女免费视频观看 | 国产真实在线 | 欧美精品乱码久久久久久 | 国产区第一页 | 免费黄色av | 日韩在线观看中文字幕 | 久久久亚洲麻豆日韩精品一区三区 | 91禁看片| 免费看成人片 | 成人av在线直播 | 国产电影黄色av | 婷婷亚洲综合五月天小说 | 免费在线观看黄网站 | 91av超碰| 日韩欧美在线中文字幕 | 欧美日韩国产伦理 | 亚洲视频在线看 | 久久免费高清 | 51久久夜色精品国产麻豆 | 999国内精品永久免费视频 | 成人av免费电影 | 黄色免费网站下载 | 国产玖玖视频 | 国产一级免费播放 | 色.com| 天堂网一区二区 | 亚洲久草网 | 亚洲精品白浆高清久久久久久 | 制服丝袜欧美 | 又长又大又黑又粗欧美 | 成年人电影毛片 | 国产美女在线观看 | 欧美综合色| 久久久久久久久福利 | 日韩av在线免费看 | 97免费视频在线播放 | 久久精品伊人 | 亚洲精品字幕 | 久久婷婷国产色一区二区三区 | 日韩视频中文字幕 | 激情五月***国产精品 | 成人午夜在线电影 | 91在线精品一区二区 | 免费av大全 | 日日夜夜免费精品 | 五月婷激情 | 91九色在线视频 | 久久精品aaa | 成年人免费在线看 | 天天射网 | www,黄视频 | 中文字幕在线视频第一页 | 欧美亚洲一区二区在线 | 日韩一区精品 | 亚洲在线高清 | 国产视频精选 | 97精品国产一二三产区 | 免费无遮挡动漫网站 | 国产永久免费观看 | 久久精品久久精品久久39 | 视频一区二区三区视频 | 97在线免费观看视频 | 亚洲中字幕 | 激情一区二区三区欧美 | 一本之道乱码区 | 欧美日韩一级久久久久久免费看 | 人人看人人艹 | 日本夜夜草视频网站 | 91视频观看免费 | 在线三级av| 久久综合中文字幕 | 国产黄色精品在线 | 一区二区三区免费在线 | 国产精品成人a免费观看 | 久久精品欧美一 | 国产一级免费电影 | 久久激情综合 | 久久久国产精品成人免费 | 久久免费福利视频 | 99精品视频一区 | 免费一级特黄录像 | 蜜臀av.com | 国产在线观看你懂得 | 久久99精品国产91久久来源 | 亚洲精品视频免费在线观看 | 国产电影黄色av | 国产1级毛片 | 久草热视频 | 麻豆一精品传二传媒短视频 | 97精品国产一二三产区 | 一区二区三区国产精品 | 日韩在线不卡视频 | 久久久受www免费人成 | 免费网址你懂的 | 色88久久| 亚洲国产97在线精品一区 | a精品视频| 狠狠色婷婷丁香六月 | 热久久这里只有精品 | 在线观看岛国 | 亚洲精品视频免费观看 | 国产精品乱码一区二区视频 | 少妇bbbb搡bbbb桶 | www.夜色.com| 久久久香蕉视频 | 超级碰碰碰免费视频 | 久久久亚洲网站 | 亚洲国产中文字幕 | 中文字幕中文字幕在线中文字幕三区 | 色婷婷综合久久久久中文字幕1 | 人人爱人人射 | 色婷婷狠狠五月综合天色拍 | 日本精品视频在线播放 | 五月天综合色激情 | 91免费视频黄 | 欧美孕妇视频 | 免费看黄色大全 | 亚洲精品久久久久中文字幕m男 | 91超级碰| 国产无区一区二区三麻豆 | 国产专区在线播放 | 激情视频在线观看网址 | 日日成人网 | 亚洲一区二区精品3399 | 日韩精品免费一区二区三区 | 色多多污污在线观看 | 黄色精品国产 | 精品免费国产一区二区三区四区 | 欧美污网站 | 国产一级视频免费看 | 久久久久久久久久久久国产精品 | 欧美日韩国产xxx | 久久综合狠狠综合久久综合88 | 成人高清在线观看 | 中文字幕第一页在线 | 亚洲最大色 | 免费观看性生活大片3 | 国产视频一区二区在线 | 国产视频一区二区在线播放 | 少妇搡bbbb搡bbb搡69 | 中文伊人 | 96亚洲精品久久久蜜桃 | 少妇搡bbbb搡bbb搡忠贞 | 一级淫片a | 久久人人爽人人爽人人片av软件 | 免费a视频在线观看 | 日本三级人妇 | av蜜桃在线| 五月婷婷另类国产 | 国产精品视频不卡 | 少妇搡bbb| 中文字幕在线观看2018 | 色综合夜色一区 | 中文字幕在线观看网 | 超级碰碰碰免费视频 | 天天射天天干天天爽 | ww视频在线观看 | 97成人在线免费视频 | 成年人黄色免费网站 | 欧美久久久久久 | 欧美一级性生活视频 | 成人av免费 | 欧美极品少妇xbxb性爽爽视频 | 精品人人人 | 五月天激情在线 | 一区在线免费观看 | 成人h在线| 国产成人a v电影 | 91精品国产欧美一区二区 | 91av视频观看 | 国偷自产视频一区二区久 | 97人人模人人爽人人喊网 | 天天精品视频 | 综合网伊人 | 九九久久影院 | 日韩欧美一区二区三区免费观看 | 国产免费激情久久 | 最新国产精品亚洲 | 伊人夜夜 | 国产精品久久一区二区无卡 | 91麻豆精品国产自产在线 | 91精品视频观看 | 黄色成人在线网站 | 成人在线免费视频 | 国产小视频福利在线 | 国产永久免费观看 | 中文字幕亚洲欧美日韩 | 中文字幕字幕中文 | 在线观看国产亚洲 | 亚洲免费av片 | 特级西西人体444是什么意思 | 国产涩涩网站 | 亚洲国产成人av网 | 亚洲欧美日韩国产 | 国产一区二区三精品久久久无广告 | 国产视频综合在线 | 伊人婷婷在线 | 97视频免费播放 | 久久婷婷视频 | 亚洲精品视频在线 | 日韩理论视频 | 国产精品久久久久久久久毛片 | 国产在线色 | 国产视频亚洲视频 | 四虎国产精品免费观看视频优播 | 国产一级性生活 | 欧美在线资源 | 国产电影一区二区三区四区 | av片子在线观看 | 色狠狠久久av五月综合 | 国产在线播放一区二区三区 | 久久艹在线| 91香蕉视频污在线 | 亚洲黄色成人 | 欧美激精品 | 欧美地下肉体性派对 | 黄色avwww| 久久激情网站 | 在线视频国产区 | 国产精品18久久久久久vr | 99爱视频 | 97超碰精品 | 狠狠色噜噜狠狠狠狠2021天天 | 国产在线91在线电影 | 日韩小视频网站 | 亚洲乱码中文字幕综合 | 91男人影院 | 精品国产免费人成在线观看 | 狠狠色狠狠色合久久伊人 | 国产高清在线不卡 | 色av网站 | 国产免费视频一区二区裸体 | 在线视频1卡二卡三卡 | 日韩欧美99 | 草久在线播放 | 91丨九色丨蝌蚪丰满 | 免费av网站在线看 | 国内精品一区二区 | 精品视频中文字幕 | 久久精久久精 | 久久久男人的天堂 | 久久久久欠精品国产毛片国产毛生 | 亚洲片在线 | www.eeuss影院av撸 | 日本福利视频在线 | 欧美日韩首页 | 成人国产精品免费观看 | 黄色a级片在线观看 | 亚洲伦理一区二区 | 欧洲精品视频一区二区 | 国产在线观看午夜 | 日日日操操 | 国产网红在线 | 欧美日韩国产网站 | 色激情在线 | 91视频高清 | 天天综合人人 | 国产手机av在线 | 欧美天天综合网 | 激情自拍av | 91九色蝌蚪国产 | 国际精品网 | 久久人人做 | 亚洲精品视频在线观看免费 | 国产99久久精品一区二区300 | 国产精品久久久久一区二区国产 | av看片在线观看 | 久久影视中文字幕 | 欧美大片第1页 | 最近中文字幕mv免费高清在线 | 色99中文字幕 | av在线网站免费观看 | 五月婷婷丁香色 | 成片人卡1卡2卡3手机免费看 | av网址aaa | 97涩涩视频| 999视频网 | 免费看av片网站 | 久久久影院一区二区三区 | 欧美 激情 国产 91 在线 | 久久久久久久久影院 | 人人dvd| 伊人导航 | 国语对白少妇爽91 | 色吊丝在线永久观看最新版本 | 激情网在线视频 | 综合网欧美 | 日韩在线观看影院 | 日韩av快播电影网 | 欧美色综合天天久久综合精品 | 日本精品一区二区在线观看 | 国产九色在线播放九色 | 免费看一级黄色大全 | 丁香六月在线观看 | 久久一久久 | 成人黄色大片 | 成人动态视频 | 国产精品成人久久久 | 免费一级片视频 | 中文字幕人成乱码在线观看 | 日韩av免费在线看 | 日韩午夜网站 | av一级久久 | 日韩高清在线不卡 | 99热9| 久久国产精品一区二区 | 久久免费99精品久久久久久 | 99久久999久久久精玫瑰 | 亚洲精品字幕 | 在线观看免费av网站 | 丁香在线| 久久r精品 | 黄色一级片视频 | 五月婷婷六月丁香激情 | 精品欧美小视频在线观看 | 精品女同一区二区三区在线观看 | 国产香蕉久久精品综合网 | 在线视频一区观看 | 国产精品毛片久久久久久久久久99999999 | 亚洲成人网在线 | 亚洲精品影视 | 亚洲国产精品电影 | 久久精品3 | 久久视频在线观看中文字幕 | 精品久久网 | 日韩乱理 | 色综合天天综合在线视频 | 久久久久成人精品亚洲国产 | 99久久精品免费看国产免费软件 | 久久电影国产免费久久电影 | 日韩欧美高清一区二区 | 91在线看| 伊人亚洲综合 | 欧美色一色| 黄色av电影 | 日韩有码第一页 | 日韩精品一区二区三区在线视频 | 97超级碰碰碰视频在线观看 | 国产亚洲高清视频 | 综合色狠狠 | 欧美激情第28页 | av高清影院| 五月天亚洲精品 | 99在线精品视频在线观看 | 国产精品免费视频观看 | www.狠狠干| 麻豆一精品传二传媒短视频 | 天堂av在线网址 | 97视频人人澡人人爽 | 日日干av | 日韩午夜一级片 | 久久99国产精品自在自在app | 国产群p | 狠狠干网站 | 免费精品人在线二线三线 | 亚洲国产精品一区二区久久hs | 亚洲国产精品成人女人久久 | 美女精品久久 | 精品色综合 | 国产一二三四在线视频 | 人人射人人爽 | 国产一区精品在线观看 | 超碰免费97 | 日本久久中文字幕 | 天天性天天草 | 中文字幕免费高清av | 国产精品久久久久久久久久久久冷 | 亚洲视频观看 | 成人黄色在线看 | 黄色中文字幕在线 | 国产毛片久久 | 国产青春久久久国产毛片 | 亚洲日本va午夜在线电影 | 免费网站黄色 | 亚洲午夜精品久久久久久久久 | 午夜精品一区二区三区在线 | 九九在线国产视频 | 久久视频精品 | 欧美另类成人 | 国产精品免费大片视频 | 亚洲国产激情 | 毛片网免费 | 久久国产免费视频 | 日韩在线视频精品 | www.久久成人 | 色偷偷网站视频 | 激情开心色 | 久久精品欧美日韩精品 | 欧美91精品久久久久国产性生爱 | 九九精品视频在线观看 | 欧美精品亚洲精品 | 狠狠干狠狠久久 | 亚洲精品国偷拍自产在线观看蜜桃 | 亚洲黄色一级大片 | 美女网站在线免费观看 | 黄色大片日本免费大片 | 一二区电影 | 欧美一级黄大片 | 91亚洲精品视频 | 国产99久久99热这里精品5 | 国产精品免费不 | 久久久精品网站 | 特级免费毛片 | 久久精品国产免费观看 | 久久在线视频在线 | 亚洲精品国产精品99久久 | 操操操日日日干干干 | 久久久成人精品 | 日日操日日 | 911精品视频| 中文字幕一区二区三区四区久久 | 激情图片区 | 久久久久久免费毛片精品 | 81国产精品久久久久久久久久 | 特级大胆西西4444www | 男女靠逼app | 亚洲精品国产综合99久久夜夜嗨 | 欧洲一区精品 | 色综合天天狠天天透天天伊人 | 国产一级二级三级在线观看 | 91福利专区 | 久久99久久99精品免视看婷婷 | 狠狠夜夜| 99国产一区| 99久久精品国产一区二区三区 | 色综合在| 国产专区精品视频 | 国产精品美女久久久久久久 | 亚洲精品视频在线观看免费视频 | 99精品欧美一区二区三区黑人哦 | 91精品视频免费观看 | 日韩免费av网址 | 视频在线观看入口黄最新永久免费国产 | 中文字幕在线一区二区三区 | 成人欧美一区二区三区黑人麻豆 | 国产片免费在线观看视频 | 亚洲少妇xxxx | 日韩免| www.国产精品| 国内精品视频免费 | 亚洲三级黄色 | 四虎欧美| www日韩欧美 | 国产精品第72页 | 色爱成人网 | 麻豆国产在线视频 | 国产手机视频在线播放 | 亚洲精品美女在线观看播放 | 波多野结衣电影久久 | 丁香电影小说免费视频观看 | 四虎在线影视 | 国产精品久免费的黄网站 | 99久久婷婷国产综合亚洲 | 亚洲国产一区二区精品专区 | 国产91九色蝌蚪 | 久久黄色免费 | 欧美日韩一二三四区 | 天天操天天射天天操 | 日韩黄色在线 | 色中文字幕在线观看 | 日日夜夜综合网 | 色吧av色av | 国产精品美女毛片真酒店 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产色资源 | 欧美91精品久久久久国产性生爱 | 日本xxxx.com | 国产视频在线播放 | 国产一区二区在线免费视频 | 欧美另类xxxxx| 亚洲国产mv | 玖玖精品在线 | 91桃色视频 | 亚洲精品黄色在线观看 | 欧美va天堂va视频va在线 | 国产在线97 | 午夜久久久久久久久久久 | 精品国产伦一区二区三区 | 欧美一级电影免费观看 | 久9在线 | 久久人人看| 91亚洲精品国偷拍 | 激情久久综合 | 日韩精品中文字幕有码 | 亚洲欧洲国产视频 | 欧美一区影院 | 日韩69视频| 热99在线视频 | 999久久久免费视频 午夜国产在线观看 | 婷婷看片 | 久久综合精品国产一区二区三区 | 国产午夜精品理论片在线 | 国产亚洲视频在线 | 国产成人精品久久二区二区 | 日韩精品在线免费播放 | 欧美激情视频在线免费观看 | 9797在线看片亚洲精品 | 91九色蝌蚪视频网站 | 久久不见久久见免费影院 | 这里只有精品视频在线观看 | 人人爱人人舔 | 久久激五月天综合精品 | 日本中文字幕在线观看 | 久久精品视频免费观看 | 九色精品| 99精品免费在线 | 99国产在线视频 | 狠狠色婷婷丁香六月 | 91成品人影院 | 亚洲欧美婷婷六月色综合 | 亚洲成年人在线播放 | 国产小视频在线观看免费 | 久草在线国产 | 久久久久www | 国产欧美日韩精品一区二区免费 | 国模一区二区三区四区 | 91久久精品日日躁夜夜躁国产 | 国产免费xvideos视频入口 | 91亚洲精品久久久蜜桃借种 | 在线视频 国产 日韩 | 成人a在线观看 | 亚洲传媒在线 | 蜜臀av夜夜澡人人爽人人 | 欧美乱码精品一区二区 | 亚洲午夜小视频 | 久久久久久影视 | 绯色av一区 | 久久69精品久久久久久久电影好 | 亚洲天堂网在线视频 | 国产精品毛片一区视频播 | 色姑娘综合天天 | 日韩欧美一区二区在线 | 91精品久 | 中文字幕资源网 国产 | 欧美aa一级 | 色婷婷久久久 | 最近中文字幕高清字幕在线视频 | 麻豆视频免费在线观看 | 99视频在线 | www.com久久| 精品资源在线 | 黄色日批网站 | 99热国产在线中文 | 婷婷在线免费 | 夜夜躁狠狠燥 | 婷婷激情影院 | 黄色一级在线观看 | 欧美精品一二 | 亚洲国产精品一区二区尤物区 | 国产成人在线播放 | 在线观看 国产 | 日日摸日日添夜夜爽97 | 808电影免费观看三年 | 国产亚洲精品美女久久 | 国产短视频在线播放 | 国产成人免费精品 | 国产高清免费视频 | 久久精美视频 | 成人蜜桃视频 | 久久最新 | 蜜臀久久99精品久久久酒店新书 | 久久a国产 | 国产精品黄网站在线观看 | 综合久久久久 | 亚洲深夜影院 | 欧美午夜一区二区福利视频 | 欧美日本不卡 | 日韩欧美国产免费播放 | 久久国产剧场电影 | 国产免费观看久久黄 | 国产午夜三级一区二区三桃花影视 | 国产精品久久久久久久久久妇女 | 日韩av成人在线 | 色婷婷狠狠五月综合天色拍 | 在线播放精品一区二区三区 | 91精品国自产在线偷拍蜜桃 | www日 | 91免费高清在线观看 | 91成人天堂久久成人 | 99热国内精品| 国产大片免费久久 | 手机av电影在线观看 | 免费高清在线视频一区· | 国产黄色av网站 | 超薄丝袜一二三区 | 超碰在97 | 天天撸夜夜操 | 91麻豆网站 | 国产盗摄精品一区二区 | 人人澡澡人人 | 粉嫩av一区二区三区四区在线观看 | 成人一级 | 色噜噜狠狠狠狠色综合久不 | 久久免费视频一区 | 日韩高清免费电影 | 成人a级大片 | 国产美女精彩久久 | 国产女v资源在线观看 | 九七视频在线 | 精品理论片 | 国产精品综合久久久久久 | 久久精品久久99 | 操高跟美女 | 91麻豆视频网站 | 久草手机视频 | 日本公妇在线观看高清 | 不卡视频一区二区三区 | 天天干天天在线 | 天天干天天做 | 91精品国产自产在线观看永久 | 久久久黄视频 | 精品夜夜嗨av一区二区三区 | 91成人天堂久久成人 | 欧美性生交大片免网 | 午夜美女福利 | 狠狠综合网 | 丁香婷婷久久久综合精品国产 | 久久婷婷精品视频 | av片在线观看免费 | 日韩婷婷| 亚洲成年人av | 免费观看特级毛片 | 人人网av | 日韩欧美在线视频一区二区三区 | 久久久高清| 精品久久久久免费极品大片 | 视频在线99re | av电影在线播放 | 91精品一区国产高清在线gif | 国产成人精品一区二区三区免费 | 国产成人精品一区二区 | 国产高清视频免费在线观看 | 国产一区二区不卡在线 | 亚洲精品资源在线 | 婷婷伊人五月天 | 黄色毛片网站在线观看 | 色姑娘综合天天 | 久久公开视频 | 国产一区二区成人 | 日韩免费一区二区 | 免费情趣视频 | 最近中文国产在线视频 | 国产免费又爽又刺激在线观看 | 日韩一区视频在线 | 国内丰满少妇猛烈精品播放 | 免费看片色| 亚洲2019精品 | 午夜视频在线观看一区二区 | av一级在线 | 欧美日韩亚洲一 | 久久爱影视i | 国产精品久久久久久久久久久久午夜 | 免费性网站 | 91香蕉国产在线观看软件 | 日韩成人在线免费观看 | 97人人人| 五月激情综合婷婷 | 深夜福利视频在线观看 | 日韩精品欧美专区 | 国产精品一区二区三区在线 | 久久看片网站 | 欧美久久电影 | 999国内精品永久免费视频 | 日韩精品首页 | 国内精品99| 在线观看麻豆av | 九九九九精品 | 欧美精品久久久久久久免费 | 7777精品伊人久久久大香线蕉 | 五月天婷婷在线观看视频 | 草久在线观看视频 | 激情文学综合丁香 | 97视频在线免费观看 | 在线观看免费一级片 | 日韩av一区二区三区在线观看 | 国产免费观看视频 | 国产精品久久久久久久久久东京 | 精品色综合 | 久久久久久久久久久久久国产精品 | 亚洲四虎 | 免费视频91 | 18pao国产成视频永久免费 | 日本一区二区高清不卡 | 久久av免费电影 | 亚洲国产精品久久 | 国产精品视频资源 | 国产精品原创av片国产免费 | 狠狠色噜噜狠狠狠 | 久久精品专区 | 91麻豆精品久久久久久 | 国产又黄又猛又粗 | 视频在线国产 | 国产麻豆精品一区二区 | 欧美亚洲国产一卡 | 日韩三级免费观看 | 狠狠干夜夜爽 | www.国产在线视频 | 久草视频2| 午夜精品一区二区三区在线播放 | 97在线精品视频 | 亚洲综合在线视频 | 国产午夜精品一区 | 国精产品999国精产品岳 | av看片网| 91九色在线观看视频 | 亚洲成人一区 | 大型av综合网站 | 97在线视频免费播放 | 色综合久久88 | 国产精品久久久久国产精品日日 | 91九色蝌蚪视频网站 | 一区二区三区在线观看中文字幕 | 国产亚洲精品久久久久秋 | 在线观看国产福利片 | 亚洲天堂首页 | 国产精品毛片一区视频播不卡 | 久久99久久精品 | 午夜精品久久久久久久99热影院 | 一级特黄aaa大片在线观看 | 一级免费黄色 | 不卡日韩av| 成年人黄色免费视频 | 黄色小网站免费看 | 在线视频日韩欧美 | 亚洲精品福利在线 | 亚洲综合成人婷婷小说 | 久久久久久在线观看 | 国产精品99久久久久久宅男 | 青青河边草观看完整版高清 | 最新中文在线视频 | 国产字幕在线观看 | 在线观看国产中文字幕 | 日韩中文字幕亚洲一区二区va在线 | 6699私人影院 | 天天干,天天射,天天操,天天摸 | 一区二区三区手机在线观看 | 超碰在线天天 | 国产999在线观看 | 国产一级在线观看视频 | 国产一区二区不卡视频 | 婷婷色五 | 色播五月激情综合网 | 久久伊人综合 | 日韩欧美在线一区 | 久久久香蕉视频 | 国产精品普通话 | 久久精品国产精品亚洲精品 | 国产传媒一区在线 | 九九久久视频 | 亚洲人人av | 久久综合色婷婷 | 中文字幕在线免费观看视频 | 98涩涩国产露脸精品国产网 | 亚洲成人免费在线观看 | 婷婷丁香激情网 | 在线а√天堂中文官网 | 久在线观看 | 久草在线视频首页 | 久久久久久久久综合 | 99精品久久久久久久久久综合 | 黄色美女免费网站 | 人人爽久久久噜噜噜电影 | 亚洲精品国产拍在线 | 久久精品一二三区白丝高潮 | 亚洲第一av在线播放 | 一区二区三区动漫 | 二区三区中文字幕 | 亚洲成av人片在线观看 | 亚洲美女免费视频 | 国产日韩av在线 | 中文字幕av最新 | 久久69av| 激情 一区二区 | 国产在线p| 久久er99热精品一区二区三区 | 99精品欧美一区二区 | 国产免费二区 | av网站播放 | 国产精品久久久久久久午夜 | 亚洲精品九九 | 欧美亚洲成人免费 | 日韩不卡高清视频 | 欧美日韩三级在线观看 | 久久精品免视看 | 久久久久久久久免费视频 | 欧美一区二区三区不卡 | 激情综合网色播五月 | 久久久久久草 | 国产69久久久| 亚洲国产精品va在线看 | 久久在线精品视频 | 欧美精品午夜 | 色噜噜在线观看 | 欧美日bb | 久久久久亚洲精品国产 | 国产色a在线观看 | 天天综合91 | 99精品国产99久久久久久福利 | 亚洲美女精品区人人人人 | 中文字幕字幕中文 | 国产精品久久久久久久久久新婚 | 亚洲国产欧美在线看片xxoo | 国产视频在线免费观看 | 一二三区在线 | 激情小说 五月 | 天天做日日做天天爽视频免费 | 国产男女免费完整视频 | 国产精品永久在线 | 有码视频在线观看 | 国产福利精品在线观看 | 日韩精品视频免费看 | 久久一线 | 色99在线 | 国产在线资源 | 亚洲国产99 | 五月天久久综合网 | 日日夜夜人人精品 | 成人av片免费看 | 久久伊人免费视频 | 免费av在 | 久久99国产精品视频 | 日韩午夜三级 | 日日夜操 | 日批视频在线 | 四虎精品成人免费网站 | 亚洲成人av在线播放 | 国产精品99蜜臀久久不卡二区 | 久久久久久久久艹 | 日韩一级网站 | 狠狠躁夜夜av | 久产久精国产品 | 欧美做受xxx | 91福利国产在线观看 | 欧美日韩国产页 | 久久欧美在线电影 | 亚洲久草网 | 在线国产视频一区 | 久精品视频免费观看2 | 国产看片免费 | 黄a网站| 亚洲午夜精 | 五月天激情婷婷 | 韩国av三级| 久久私人影院 | 国产视频中文字幕 | 国产精品美女久久久久久久久 | 日韩电影在线看 | 最新中文在线视频 | 成人福利在线 | 欧美激情视频免费看 | 久久a级片 | 婷婷天天色 | 在线亚洲人成电影网站色www | 成人天堂网 | 亚洲精品日韩av | 91精品资源 | 婷婷色在线视频 | 碰超在线观看 | 日韩精品一区二区三区外面 | 1000部18岁以下禁看视频 | 91精品秘密在线观看 | 久久婷婷国产色一区二区三区 | 二区三区精品 | 国产高清免费在线播放 | 亚洲精品一区二区三区在线观看 | 51精品国自产在线 | 国产精品女主播一区二区三区 | 国产原创在线观看 | 日韩高清在线看 | 久久综合久久综合久久综合 | 91精品视频在线免费观看 | 欧美中文字幕久久 | 婷婷www| 中文字幕4 | av成人免费在线 | 18国产精品白浆在线观看免费 | 欧美另类激情 | 亚洲九九九在线观看 | 欧美视频国产视频 | 亚洲一区免费在线 | 日日夜夜天天射 | 亚洲传媒在线 | av高清网站在线观看 | 日韩av一区二区三区在线观看 | 中文字幕一区在线 | 91精品办公室少妇高潮对白 | 永久免费毛片在线观看 | 五月花激情| 成人av手机在线 | 91九色视频在线播放 | 欧美一二三区在线观看 | 久久99久久精品国产 | 91久久黄色 | 日韩毛片在线一区二区毛片 | 在线免费看黄网站 | 深爱综合网 | 国产精品免费观看网站 | 999久久久欧美日韩黑人 | 久草视频2| 在线免费观看羞羞视频 | 四虎在线免费观看 | 激情婷婷色 | 国产精品久久久久一区二区国产 | 色综合在| www.色婷婷.com | 一区二区三区视频网站 | 免费观看v片在线观看 | 亚洲精品视频在线观看网站 | 久久国产精品视频免费看 | 亚洲片在线资源 | 狠狠狠色丁香婷婷综合久久五月 | 色999精品 | 久久影视一区二区 | zzijzzij亚洲日本少妇熟睡 | 超碰日韩在线 | 九九热.com| 天天操天天色天天射 | 操高跟美女 | 97超级碰碰碰视频在线观看 | 最近能播放的中文字幕 | 91日韩精品 | 蜜桃av观看 | 99草在线视频 | 亚洲精品在线二区 | 免费看一级一片 | 中文字幕91 | 精品免费视频. | 99综合电影在线视频 | 97超碰伊人 | 在线精品视频在线观看高清 | 欧美精品三级在线观看 | 黄色电影在线免费观看 | 国产一级精品在线观看 | 久久成电影 | 欧美精品乱码久久久久 | 精品免费国产一区二区三区四区 | 人人射网站 | 色婷婷综合五月 | 国产成人综合在线观看 | 五月天婷婷综合 | 久久九九精品久久 | 国产 一区二区三区 在线 | 国产成人精品综合久久久 | 国产区高清在线 | 欧美伦理一区二区 | 亚洲免费不卡 | 在线影院中文字幕 | 亚洲精品视频中文字幕 | 国产综合小视频 | 国产精品视频 | 一级一片免费看 | 免费毛片aaaaaa | 精品乱码一区二区三四区 | 亚洲乱亚洲乱妇 | 1000部国产精品成人观看 | 欧美一级日韩免费不卡 | 久久久久综合视频 | 亚洲黄色片在线 |