精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從頭開始進(jìn)行CUDA編程:線程間協(xié)作的常見技術(shù)

開發(fā) 前端
在前一篇文章中,我們介紹了如何使用 GPU 運(yùn)行的并行算法。這些并行任務(wù)是那些完全相互獨(dú)立的任務(wù),這點(diǎn)與我們一般認(rèn)識的編程方式有很大的不同,雖然我們可以從并行中受益,但是這種奇葩的并行運(yùn)行方式對于我們來說肯定感到非常的復(fù)雜。

在前一篇文章中,我們介紹了如何使用 GPU 運(yùn)行的并行算法。這些并行任務(wù)是那些完全相互獨(dú)立的任務(wù),這點(diǎn)與我們一般認(rèn)識的編程方式有很大的不同,雖然我們可以從并行中受益,但是這種奇葩的并行運(yùn)行方式對于我們來說肯定感到非常的復(fù)雜。所以在本篇文章的Numba代碼中,我們將介紹一些允許線程在計(jì)算中協(xié)作的常見技術(shù)。

首先還是載入相應(yīng)的包

from time import perf_counter

import numpy as np

import numba
from numba import cuda

print(np.__version__)
print(numba.__version__)

cuda.detect()

# 1.21.6
# 0.55.2

# Found 1 CUDA devices
# id 0 b'Tesla T4' [SUPPORTED]
# Compute Capability: 7.5
# PCI Device ID: 4
# PCI Bus ID: 0
# UUID: GPU-bcc6196e-f26e-afdc-1db3-6eba6ff160f0
# Watchdog: Disabled
# FP32/FP64 Performance Ratio: 32
# Summary:
# 1/1 devices are supported
# True

不要忘記,我們這里是CUDA編程,所以NV的GPU是必須的,比如可以去colab或者Kaggle白嫖。

線程間的協(xié)作

簡單的并行歸約算法

我們將從一個非常簡單的問題開始本節(jié):對數(shù)組的所有元素求和。這個算法非常簡單。如果不使用NumPy,我們可以這樣實(shí)現(xiàn)它:

 def sum_cpu(array):
s = 0.0
for i in range(array.size):
s += array[i]
return s

這看起來不是很 Pythonic。但它能夠讓我們了解它正在跟蹤數(shù)組中的所有元素。如果 s 的結(jié)果依賴于數(shù)組的每個元素,我們?nèi)绾尾⑿谢@個算法呢?首先,我們需要重寫算法以允許并行化, 如果有無法并行化的部分則應(yīng)該允許線程相互通信。

到目前為止,我們還沒有學(xué)會如何讓線程相互通信……事實(shí)上,我們之前說過不同塊中的線程不通信。我們可以考慮只啟動一個塊,但是我們上次也說了,在大多數(shù) GPU 中塊只能有 1024 個線程!

如何克服這一點(diǎn)?如果將數(shù)組拆分為 1024 個塊(或適當(dāng)數(shù)量的threads_per_block)并分別對每個塊求和呢?然后最后,我們可以將每個塊的總和的結(jié)果相加。下圖顯示了一個非常簡單的 2 塊拆分示例。

上圖就是對數(shù)組元素求和的“分而治之”方法。

如何在 GPU 上做到這一點(diǎn)呢?首先需要將數(shù)組拆分為塊。每個數(shù)組塊將只對應(yīng)一個具有固定數(shù)量的線程的CUDA塊。在每個塊中,每個線程可以對多個數(shù)組元素求和。然后將這些每個線程的值求和,這里就需要線程進(jìn)行通信,我們將在下一個示例中討論如何通信。

由于我們正在對塊進(jìn)行并行化,因此內(nèi)核的輸出應(yīng)該被設(shè)置為一個塊。為了完成Reduce,我們將其復(fù)制到 CPU 并在那里完成工作。

threads_per_block = 1024 # Why not!
blocks_per_grid = 32 * 80 # Use 32 * multiple of streaming multiprocessors

# Example 2.1: Naive reduction
@cuda.jit
def reduce_naive(array, partial_reduction):
i_start = cuda.grid(1)
threads_per_grid = cuda.blockDim.x * cuda.gridDim.x
s_thread = 0.0
for i_arr in range(i_start, array.size, threads_per_grid):
s_thread += array[i_arr]

# We need to create a special *shared* array which will be able to be read
# from and written to by every thread in the block. Each block will have its
# own shared array. See the warning below!
s_block = cuda.shared.array((threads_per_block,), numba.float32)

# We now store the local temporary sum of a single the thread into the
# shared array. Since the shared array is sized
# threads_per_block == blockDim.x
# (1024 in this example), we should index it with `threadIdx.x`.
tid = cuda.threadIdx.x
s_block[tid] = s_thread

# The next line synchronizes the threads in a block. It ensures that after
# that line, all values have been written to `s_block`.
cuda.syncthreads()

# Finally, we need to sum the values from all threads to yield a single
# value per block. We only need one thread for this.
if tid == 0:
# We store the sum of the elements of the shared array in its first
# coordinate
for i in range(1, threads_per_block):
s_block[0] += s_block[i]
# Move this partial sum to the output. Only one thread is writing here.
partial_reduction[cuda.blockIdx.x] = s_block[0]

這里需要注意的是必須共享數(shù)組,并且讓每個數(shù)組塊變得“小”

這里的“小”:確切大小取決于 GPU 的計(jì)算能力,通常在 48 KB 和 163 KB 之間。請參閱此表中的??“每個線程塊的最大共享內(nèi)存量??”項(xiàng)。

在編譯時有一個已知的大小(這就是我們調(diào)整共享數(shù)組threads_per_block而不是blockDim.x的原因)。我們總是可以為任何大小的共享數(shù)組定義一個工廠函數(shù)……但要注意這些內(nèi)核的編譯時間。

這里的數(shù)組需要為 Numba 類型指定的 dtype,而不是 Numpy 類型(這個沒有為什么!)。

 N = 1_000_000_000
a = np.arange(N, dtype=np.float32)
a /= a.sum() # a will have sum = 1 (to float32 precision)

s_cpu = a.sum()

# Highly-optimized NumPy CPU code
timing_cpu = np.empty(21)
for i in range(timing_cpu.size):
tic = perf_counter()
a.sum()
toc = perf_counter()
timing_cpu[i] = toc - tic
timing_cpu *= 1e3 # convert to ms

print(f"Elapsed time CPU: {timing_cpu.mean():.0f} ± {timing_cpu.std():.0f} ms")
# Elapsed time CPU: 354 ± 24 ms

dev_a = cuda.to_device(a)
dev_partial_reduction = cuda.device_array((blocks_per_grid,), dtype=a.dtype)

reduce_naive[blocks_per_grid, threads_per_block](dev_a, dev_partial_reduction)
s = dev_partial_reduction.copy_to_host().sum() # Final reduction in CPU

np.isclose(s, s_cpu) # Ensure we have the right number
# True

timing_naive = np.empty(21)
for i in range(timing_naive.size):
tic = perf_counter()
reduce_naive[blocks_per_grid, threads_per_block](dev_a, dev_partial_reduction)
s = dev_partial_reduction.copy_to_host().sum()
cuda.synchronize()
toc = perf_counter()
assert np.isclose(s, s_cpu)
timing_naive[i] = toc - tic
timing_naive *= 1e3 # convert to ms

print(f"Elapsed time naive: {timing_naive.mean():.0f} ± {timing_naive.std():.0f} ms")
# Elapsed time naive: 30 ± 12 ms

在谷歌Colab上測試,得到了10倍的加速。

題外話:上面這個方法之所以說是簡單的規(guī)約算法,是因?yàn)檫@個算法最簡單,也最容易實(shí)現(xiàn)。我們在大數(shù)據(jù)中常見的Map-Reduce算法就是這個算法。雖然實(shí)現(xiàn)簡單,但是他容易理解,所以十分常見,當(dāng)然他慢也是出名的,有興趣的大家可以去研究研究。

一種更好的并行歸約算法

上面的算法最 “樸素”的,所以有很多技巧可以加快這種代碼的速度(請參閱 CUDA 演示文稿中的 Optimizing Parallel Reduction 以獲得基準(zhǔn)測試)。

在介紹更好的方法之前,讓我們回顧一下內(nèi)核函數(shù)的的最后一點(diǎn):

 if tid == 0: # Single thread taking care of business
for i in range(1, threads_per_block):
s_block[0] += s_block[i]
partial_reduction[cuda.blockIdx.x] = s_block[0]

我們并行化了幾乎所有的操作,但是在內(nèi)核的最后,讓一個線程負(fù)責(zé)對共享數(shù)組 s_block 的所有 threads_per_block 元素求和。為什么不能把這個總和也并行化呢?

聽起來不錯對吧,下圖顯示了如何在 threads_per_block 大小為 16 的情況下實(shí)現(xiàn)這一點(diǎn)。我們從 8 個線程開始工作,第一個將對 s_block[0] 和 s_block[8] 中的值求和。第二個求和s_block[1]和s_block[9]中的值,直到最后一個線程將s_block[7]和s_block[15]的值相加。

在下一步中,只有前 4 個線程需要工作。第一個線程將對 s_block[0] 和 s_block[4] 求和;第二個,s_block[1] 和 s_block[5];第三個,s_block[2] 和 s_block[6];第四個也是最后一個,s_block[3] 和 s_block[7]。

第三步,只需要 2 個線程來處理 s_block 的前 4 個元素。

第四步也是最后一步將使用一個線程對 2 個元素求和。

由于工作已在線程之間分配,因此它是并行化的。這不是每個線程的平等劃分,但它是一種改進(jìn)。在計(jì)算上,這個算法是 O(log2(threads_per_block)),而上面“樸素”算法是 O(threads_per_block)。比如在我們這個示例中是 1024 次操作,用于 了兩個算法差距有10倍

最后還有一個細(xì)節(jié)。在每一步,我們都需要確保所有線程都已寫入共享數(shù)組。所以我們必須調(diào)用 cuda.syncthreads()。

 # Example 2.2: Better reduction
@cuda.jit
def reduce_better(array, partial_reduction):
i_start = cuda.grid(1)
threads_per_grid = cuda.blockDim.x * cuda.gridDim.x
s_thread = 0.0
for i_arr in range(i_start, array.size, threads_per_grid):
s_thread += array[i_arr]

# We need to create a special *shared* array which will be able to be read
# from and written to by every thread in the block. Each block will have its
# own shared array. See the warning below!
s_block = cuda.shared.array((threads_per_block,), numba.float32)

# We now store the local temporary sum of the thread into the shared array.
# Since the shared array is sized threads_per_block == blockDim.x,
# we should index it with `threadIdx.x`.
tid = cuda.threadIdx.x
s_block[tid] = s_thread

# The next line synchronizes the threads in a block. It ensures that after
# that line, all values have been written to `s_block`.
cuda.syncthreads()

i = cuda.blockDim.x // 2
while (i > 0):
if (tid < i):
s_block[tid] += s_block[tid + i]
cuda.syncthreads()
i //= 2

if tid == 0:
partial_reduction[cuda.blockIdx.x] = s_block[0]


reduce_better[blocks_per_grid, threads_per_block](dev_a, dev_partial_reduction)
s = dev_partial_reduction.copy_to_host().sum() # Final reduction in CPU

np.isclose(s, s_cpu)
# True

timing_naive = np.empty(21)
for i in range(timing_naive.size):
tic = perf_counter()
reduce_better[blocks_per_grid, threads_per_block](dev_a, dev_partial_reduction)
s = dev_partial_reduction.copy_to_host().sum()
cuda.synchronize()
toc = perf_counter()
assert np.isclose(s, s_cpu)
timing_naive[i] = toc - tic
timing_naive *= 1e3 # convert to ms

print(f"Elapsed time better: {timing_naive.mean():.0f} ± {timing_naive.std():.0f} ms")
# Elapsed time better: 22 ± 1 ms

可以看到,這比原始方法快25%。

重要說明:你可能很想將同步線程移動到 if 塊內(nèi),因?yàn)樵诿恳徊街螅^當(dāng)前線程數(shù)一半的內(nèi)核將不會被使用。但是這樣做會使調(diào)用同步線程的 CUDA 線程停止并等待所有其他線程,而所有其他線程將繼續(xù)運(yùn)行。因此停止的線程將永遠(yuǎn)等待永遠(yuǎn)不會停止同步的線程。如果您同步線程,請確保在所有線程中調(diào)用 cuda.syncthreads()。

 i = cuda.blockDim.x // 2
while (i > 0):
if (tid < i):
s_block[tid] += s_block[tid + i]
#cuda.syncthreads() 這個是錯的
cuda.syncthreads() # 這個是對的
i //= 2

Numba 自動歸約

其實(shí)歸約算法并不簡單,所以Numba 提供了一個方便的 cuda.reduce 裝飾器,可以將二進(jìn)制函數(shù)轉(zhuǎn)換為歸約。所以上面冗長而復(fù)雜的算法可以替換為:

@cuda.reduce
def reduce_numba(a, b):
return a + b

# Compile and check
s = reduce_numba(dev_a)

np.isclose(s, s_cpu)
# True

# Time
timing_numba = np.empty(21)
for i in range(timing_numba.size):
tic = perf_counter()
s = reduce_numba(dev_a)
toc = perf_counter()
assert np.isclose(s, s_cpu)
timing_numba[i] = toc - tic
timing_numba *= 1e3 # convert to ms

print(f"Elapsed time better: {timing_numba.mean():.0f} ± {timing_numba.std():.0f} ms")
# Elapsed time better: 45 ± 0 ms

上面的運(yùn)行結(jié)果我們可以看到手寫代碼通常要快得多(至少 2 倍),但 Numba 給我們提供的方法卻非常容易使用。這對我們來說是格好事,因?yàn)榻K于有我們自己實(shí)現(xiàn)的Python方法比官方的要快了??

這里還有一點(diǎn)要注意就是默認(rèn)情況下,要減少復(fù)制因?yàn)檫@會強(qiáng)制同步。為避免這種情況可以使用設(shè)備上數(shù)組作為輸出調(diào)用歸約:

dev_s = cuda.device_array((1,), dtype=s)

reduce_numba(dev_a, res=dev_s)

s = dev_s.copy_to_host()[0]
np.isclose(s, s_cpu)
# True

二維規(guī)約示例

并行約簡技術(shù)是非常偉大的,如何將其擴(kuò)展到更高的維度?雖然我們總是可以使用一個展開的數(shù)組(array2 .ravel())調(diào)用,但了解如何手動約簡多維數(shù)組是很重要的。

在下面這個例子中,將結(jié)合剛才所學(xué)的知識來計(jì)算二維數(shù)組。

 threads_per_block_2d = (16, 16) # 256 threads total
blocks_per_grid_2d = (64, 64)

# Total number of threads in a 2D block (has to be an int)
shared_array_len = int(np.prod(threads_per_block_2d))

# Example 2.4: 2D reduction with 1D shared array
@cuda.jit
def reduce2d(array2d, partial_reduction2d):
ix, iy = cuda.grid(2)
threads_per_grid_x, threads_per_grid_y = cuda.gridsize(2)

s_thread = 0.0
for i0 in range(iy, array2d.shape[0], threads_per_grid_x):
for i1 in range(ix, array2d.shape[1], threads_per_grid_y):
s_thread += array2d[i0, i1]

# Allocate shared array
s_block = cuda.shared.array(shared_array_len, numba.float32)

# Index the threads linearly: each tid identifies a unique thread in the
# 2D grid.
tid = cuda.threadIdx.x + cuda.blockDim.x * cuda.threadIdx.y
s_block[tid] = s_thread

cuda.syncthreads()

# We can use the same smart reduction algorithm by remembering that
# shared_array_len == blockDim.x * cuda.blockDim.y
# So we just need to start our indexing accordingly.
i = (cuda.blockDim.x * cuda.blockDim.y) // 2
while (i != 0):
if (tid < i):
s_block[tid] += s_block[tid + i]
cuda.syncthreads()
i //= 2

# Store reduction in a 2D array the same size as the 2D blocks
if tid == 0:
partial_reduction2d[cuda.blockIdx.x, cuda.blockIdx.y] = s_block[0]


N_2D = (20_000, 20_000)
a_2d = np.arange(np.prod(N_2D), dtype=np.float32).reshape(N_2D)
a_2d /= a_2d.sum() # a_2d will have sum = 1 (to float32 precision)

s_2d_cpu = a_2d.sum()

dev_a_2d = cuda.to_device(a_2d)
dev_partial_reduction_2d = cuda.device_array(blocks_per_grid_2d, dtype=a.dtype)

reduce2d[blocks_per_grid_2d, threads_per_block_2d](dev_a_2d, dev_partial_reduction_2d)
s_2d = dev_partial_reduction_2d.copy_to_host().sum() # Final reduction in CPU

np.isclose(s_2d, s_2d_cpu) # Ensure we have the right number
# True

timing_2d = np.empty(21)
for i in range(timing_2d.size):
tic = perf_counter()
reduce2d[blocks_per_grid_2d, threads_per_block_2d](dev_a_2d, dev_partial_reduction_2d)
s_2d = dev_partial_reduction_2d.copy_to_host().sum()
cuda.synchronize()
toc = perf_counter()
assert np.isclose(s_2d, s_2d_cpu)
timing_2d[i] = toc - tic
timing_2d *= 1e3 # convert to ms

print(f"Elapsed time better: {timing_2d.mean():.0f} ± {timing_2d.std():.0f} ms")
# Elapsed time better: 15 ± 4 ms

設(shè)備函數(shù)

到目前為止,我們只討論了內(nèi)核函數(shù),它是啟動線程的特殊GPU函數(shù)。內(nèi)核通常依賴于較小的函數(shù),這些函數(shù)在GPU中定義,只能訪問GPU數(shù)組。這些被稱為設(shè)備函數(shù)(Device functions)。與內(nèi)核函數(shù)不同的是,它們可以返回值。

我們將展示一個跨不同內(nèi)核使用設(shè)備函數(shù)的示例。該示例還將展示在使用共享數(shù)組時同步線程的重要性。

在CUDA的新版本中,內(nèi)核可以啟動其他內(nèi)核。這被稱為動態(tài)并行,但是Numba 的CUDA API還不支持。

我們將在固定大小的數(shù)組中創(chuàng)建波紋圖案。首先需要聲明將使用的線程數(shù),因?yàn)檫@是共享數(shù)組所需要的。

 threads_16 = 16

import math

@cuda.jit(device=True, inline=True) # inlining can speed up execution
def amplitude(ix, iy):
return (1 + math.sin(2 * math.pi * (ix - 64) / 256)) * (
1 + math.sin(2 * math.pi * (iy - 64) / 256)
)

# Example 2.5a: 2D Shared Array
@cuda.jit
def blobs_2d(array2d):
ix, iy = cuda.grid(2)
tix, tiy = cuda.threadIdx.x, cuda.threadIdx.y

shared = cuda.shared.array((threads_16, threads_16), numba.float32)
shared[tiy, tix] = amplitude(iy, ix)
cuda.syncthreads()

array2d[iy, ix] = shared[15 - tiy, 15 - tix]

# Example 2.5b: 2D Shared Array without synchronize
@cuda.jit
def blobs_2d_wrong(array2d):
ix, iy = cuda.grid(2)
tix, tiy = cuda.threadIdx.x, cuda.threadIdx.y

shared = cuda.shared.array((threads_16, threads_16), numba.float32)
shared[tiy, tix] = amplitude(iy, ix)

# When we don't sync threads, we may have not written to shared
# yet, or even have overwritten it by the time we write to array2d
array2d[iy, ix] = shared[15 - tiy, 15 - tix]


N_img = 1024
blocks = (N_img // threads_16, N_img // threads_16)
threads = (threads_16, threads_16)

dev_image = cuda.device_array((N_img, N_img), dtype=np.float32)
dev_image_wrong = cuda.device_array((N_img, N_img), dtype=np.float32)

blobs_2d[blocks, threads](dev_image)
blobs_2d_wrong[blocks, threads](dev_image_wrong)

image = dev_image.copy_to_host()
image_wrong = dev_image_wrong.copy_to_host()

import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.imshow(image.T, cmap="nipy_spectral")
ax2.imshow(image_wrong.T, cmap="nipy_spectral")
for ax in (ax1, ax2):
ax.set_xticks([])
ax.set_yticks([])
ax.set_xticklabels([])
ax.set_yticklabels([])

圖片

左:同步(正確)內(nèi)核的結(jié)果。正確:來自不同步(不正確)內(nèi)核的結(jié)果。

總結(jié)

本文介紹了如何開發(fā)需要規(guī)約模式來處理1D和2D數(shù)組的內(nèi)核函數(shù)。在這個過程中,我們學(xué)習(xí)了如何利用共享數(shù)組和設(shè)備函數(shù)。如果你對文本感興趣,請看源代碼:

https://colab.research.google.com/drive/1GkGLDexnYUnl2ilmwNxAlWAH6Eo5ZK2f?usp=sharing

責(zé)任編輯:華軒 來源: DeepHub IMBA
相關(guān)推薦

2022-11-23 16:20:12

GPU編程流和事件開發(fā)

2013-01-08 11:02:26

IBMdW

2013-05-23 10:10:53

PHP5.5PHP編譯php

2009-05-08 09:40:07

網(wǎng)易魔獸暴雪

2020-11-17 08:09:01

webpack配置項(xiàng)腳手架

2021-06-04 22:43:32

Python本地搜索

2023-05-24 16:20:39

DevOpsCI/CD 管道軟件開發(fā)

2022-06-01 23:21:34

Python回歸樹數(shù)據(jù)

2023-06-08 08:21:08

多線程編程線程間通信

2021-02-20 21:29:40

GitHub代碼開發(fā)者

2023-02-06 16:01:26

數(shù)據(jù)中心服務(wù)器

2020-06-11 08:32:50

Python遺傳算法代碼

2017-02-23 08:45:36

Python決策樹數(shù)據(jù)集

2023-08-11 17:30:54

決策樹機(jī)器學(xué)習(xí)算法

2021-07-06 14:21:05

物聯(lián)網(wǎng)智慧城市網(wǎng)絡(luò)安全

2022-11-14 10:49:33

Linux發(fā)行版

2017-08-28 18:41:34

PythonLogistic回歸隨機(jī)梯度下降

2022-09-20 10:18:05

論文技術(shù)

2024-03-20 12:44:35

AI訓(xùn)練

2024-09-26 16:51:23

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

国产精品无圣光一区二区| 久久香蕉精品| 亚洲女人天堂网| 久久国产激情视频| 日韩精品亚洲人成在线观看| 99久久伊人精品| 国产精品私拍pans大尺度在线 | 性插视频在线观看| 美女看a上一区| 国产+成+人+亚洲欧洲| 69视频在线观看免费| 1769国产精品视频| 欧美日韩的一区二区| 国产96在线 | 亚洲| 欧美尤物美女在线| 久久久亚洲精品石原莉奈| 波多野结衣一区二区三区在线观看| 波多野结衣国产| 亚洲精品小说| 在线观看国产欧美| 男男做爰猛烈叫床爽爽小说 | 咪咪网在线视频| 亚洲欧美日韩久久| 亚洲人成77777| 人人九九精品| 播五月开心婷婷综合| 亚洲va久久久噜噜噜久久天堂| 6080午夜伦理| 国产精品久久久久久久久久妞妞 | 亚洲一区精彩视频| 国产三级视频在线播放线观看| 成人毛片视频在线观看| 亚洲一区二区三区在线视频 | 吴梦梦av在线| 亚洲s色大片| 国产三级一区二区| 日韩经典在线视频| 男女污视频在线观看| 99精品欧美一区| 国模精品一区二区三区| 丰满人妻熟女aⅴ一区| 国产麻豆精品theporn| 国产免费观看久久黄| 五月激情丁香网| 视频一区免费在线观看| 日韩av男人的天堂| 中文在线第一页| 天堂蜜桃91精品| 欧美专区在线播放| 亚洲欧美日韩激情| 久久久噜噜噜| 国产精品欧美久久久| 少妇一级淫片日本| 蜜臀av一区二区三区| 国产免费一区二区三区香蕉精| 中文字幕在线观看1| 麻豆一区二区99久久久久| 国产精品综合网站| 91亚洲国产成人精品一区| 久久精品国产精品青草| 91精品在线播放| 丰满人妻一区二区三区免费视频| 国产成人精品午夜视频免费| 粉嫩av一区二区三区免费观看 | 日日夜夜亚洲| 欧美一区二区视频在线观看2022| 日本55丰满熟妇厨房伦| 都市激情亚洲欧美| 亚洲欧美中文日韩v在线观看| 四虎国产精品成人免费入口| 日本不卡免费一区| 久久成人人人人精品欧| 国产一级片视频| 亚洲精品人人| 国产精品91久久久| 国产精品日韩无码| av网站一区二区三区| 日韩精品不卡| 成人黄色网址| 午夜av一区二区三区| 欧美性猛交久久久乱大交小说| 欧美性生活一级| 欧美精品一区二区三区蜜桃视频| 中文字幕在线免费看线人 | 色哟哟免费网站| www.色在线| 欧美在线观看18| 国产91在线免费观看| 欧美一区二区三区久久| 中文字幕在线成人| 日本在线视频中文字幕| 日产欧产美韩系列久久99| 亚洲在线一区二区| 日本v片在线免费观看| 综合久久久久久久| 91专区在线观看| 色成人综合网| 日韩高清a**址| 少妇高潮一区二区三区喷水| 99精品99| 亚洲精品欧美日韩| 欧美女子与性| 亚洲电影中文字幕在线观看| 天堂中文视频在线| 久久这里只有精品一区二区| 日韩亚洲综合在线| 在线免费黄色av| 国产成a人无v码亚洲福利| 欧美国产综合视频| 免费男女羞羞的视频网站在线观看| 色天使色偷偷av一区二区| 少妇伦子伦精品无吗| 色婷婷色综合| 日本精品免费一区二区三区| www黄色在线观看| 国产精品久久久久久亚洲伦| 男人揉女人奶房视频60分 | 亚洲成年人影院在线| 国产精品视频看看| 日韩精品免费专区| 蜜桃精品久久久久久久免费影院 | 亚洲精品国产一区二区精华液| 一本久道综合色婷婷五月| 女同另类激情重口| 欧美激情视频一区二区三区不卡| 亚洲怡红院av| 中文字幕精品一区| 嫩草av久久伊人妇女超级a| 欧美色图五月天| 国内成人精品一区| 蜜桃久久一区二区三区| 亚洲综合男人的天堂| 91网址在线观看精品| 久久精品久久久| 国产精品欧美一区二区| 国产二区在线播放| 日本黄色一区二区| 国产精品无码久久久久一区二区| 亚洲高清在线| 国产专区一区二区三区| 黄视频免费在线看| 日韩av在线一区二区| 日本五十熟hd丰满| 99久久国产综合精品麻豆| 18禁裸男晨勃露j毛免费观看| 操欧美女人视频| 97精品免费视频| 四虎电影院在线观看| 日韩欧美中文在线| 少妇av片在线观看| 美女性感视频久久| 天天综合中文字幕| 人人九九精品视频| 高清欧美一区二区三区| 神马午夜一区二区| 高潮白浆女日韩av免费看| 成年人网站免费在线观看 | 国产精品久久久久久超碰| www.视频在线.com| 欧美精品在欧美一区二区少妇| 精品少妇一区二区三区密爱| 国产揄拍国内精品对白| 久久这里只有精品8| 欧美精品国产白浆久久久久| 国产99久久久欧美黑人| 欧美激情午夜| 亚洲大胆人体视频| 丁香社区五月天| 亚洲欧美中日韩| 国产伦理在线观看| 欧美中文字幕| 伊人久久99| 久久动漫网址| 国产精品人成电影| 污污网站在线观看| 亚洲人成毛片在线播放| 91一区二区视频| 亚洲www啪成人一区二区麻豆| 一区二区黄色片| 国产精品自拍一区| 99精品视频在线看| 欧美丰满日韩| 精品视频导航| 日韩午夜电影免费看| 欧美夫妻性生活视频| 成人免费黄色网页| 欧美videos中文字幕| 国产无遮挡又黄又爽又色视频| 成人欧美一区二区三区| 9.1成人看片| 激情六月婷婷综合| 男人天堂网视频| 欧美不卡高清| 日韩av免费电影| 99a精品视频在线观看| 国产精品久久久久一区二区| 午夜影院免费在线| 亚洲偷熟乱区亚洲香蕉av| 国产黄色大片网站| 欧美羞羞免费网站| 久久国产精品系列| 亚洲精品成a人| 成人在线观看免费高清| 99re成人精品视频| 91人妻一区二区三区| 蜜臀久久久99精品久久久久久| 免费网站在线观看视频| 日韩在线观看| 日韩av高清| 亚洲电影一级片| 国产精品日本一区二区| 91精品视频一区二区| 国产精品999| 色是在线视频| 午夜美女久久久久爽久久| 超碰超碰在线| xvideos亚洲| 成人欧美亚洲| 国产一区二区三区四区福利| 亚洲色偷精品一区二区三区| 精品国产一区二区三区av性色| 国产精品一区二区免费视频| 欧美色图在线观看| 亚洲 小说区 图片区| 一本色道综合亚洲| 日日骚av一区二区| 天天av天天翘天天综合网 | 免费久久99精品国产自在现线| 国产精品自拍合集| 国语对白精品一区二区| 特级西西人体www高清大胆| 91亚洲国产| 亚洲永久激情精品| 久久综合av| 一区二区三区四区欧美日韩| 日本黄色精品| 欧美综合激情| 精品视频免费| 亚洲啪啪av| 国产大片一区| 亚洲五码在线观看视频| 欧美黄色一区二区| 轻点好疼好大好爽视频| 国内揄拍国内精品久久| 成人免费性视频| 亚洲福利国产| av片中文字幕| 免费看日韩精品| 中文字幕日韩综合| 国产精品一二三四五| 久久久久无码国产精品一区李宗瑞 | 一二三区精品福利视频| 国产在线视频第一页| 无吗不卡中文字幕| 久久99国产综合精品免费| 日本久久精品电影| 在线观看日韩一区二区| 91.麻豆视频| 亚洲精品18在线观看| 国产视频欧美视频| 色大18成网站www在线观看| 久久手机免费视频| 国内在线视频| 欧美在线播放视频| 国产成人毛片| 亚洲综合在线播放| 偷拍亚洲色图| 亚洲电影一二三区| 欧美黄色aaaa| 国产免费毛卡片| 久久99精品国产.久久久久久| 欧美国产在线一区| 91蜜桃婷婷狠狠久久综合9色| 无码少妇精品一区二区免费动态| 中文字幕综合网| www成人在线| 欧美人动与zoxxxx乱| 人妻妺妺窝人体色www聚色窝| 亚洲女人天堂成人av在线| 国产网友自拍视频导航网站在线观看| 欧美激情啊啊啊| 欧美成人精品一区二区男人小说| 成人久久一区二区| 美女视频免费精品| 亚洲一区二区三区精品在线观看| 欧美日韩精选| 色悠悠久久综合网| 成人激情小说网站| 日韩在线不卡av| 黑人精品xxx一区一二区| 国产毛片毛片毛片毛片毛片| 日韩高清中文字幕| 日韩免费影院| 国产日韩欧美影视| 亚洲福利网站| 成人小视频在线观看免费| 日本中文字幕不卡| 久久久午夜精品福利内容| 中文字幕一区二区三区不卡 | 三级久久三级久久久| 日韩精品――色哟哟| 国产精品三级av| 日韩不卡视频在线| 日韩欧美中文字幕制服| 成年在线观看免费人视频| 91精品国产成人| 一区三区自拍| 在线免费一区| 日韩av电影天堂| 国产精品第七页| 亚洲一区二区成人在线观看| 中文字幕视频在线播放| 日韩电影大片中文字幕| 污污的网站在线免费观看| 国产在线视频2019最新视频| 欧美美乳视频| www.玖玖玖| 白白色亚洲国产精品| 在线免费日韩av| 欧美片在线播放| 第一页在线观看| 人妖精品videosex性欧美| 另类尿喷潮videofree| 免费网站永久免费观看| 国产精选一区二区三区| 欧美丰满熟妇bbbbbb| 欧美日韩亚洲高清一区二区| 国产乱理伦片a级在线观看| 91超碰中文字幕久久精品| 成人av动漫| 国产真人做爰毛片视频直播| 国产91露脸合集magnet| 欧美成人一二三区| 欧美一级片免费看| 91中文在线| 91国产在线免费观看| 牛牛国产精品| 久久久久亚洲av无码专区首jn| 亚洲精品乱码久久久久久黑人| 国产av无码专区亚洲av麻豆| 久久亚洲成人精品| 日本亚州欧洲精品不卡| av日韩在线看| 成人动漫一区二区三区| 少妇一级淫片免费放中国| 精品在线观看国产| 国模一区二区| 中文字幕在线中文字幕日亚韩一区| 久久成人麻豆午夜电影| 黄色片子在线观看| 欧美一区二区三区免费视频 | 欧美双性人妖o0| 精品国产精品自拍| 加勒比一区二区三区在线| 国产精品久久久久高潮| 99久久99热这里只有精品| 美女日批在线观看| 午夜精品一区二区三区三上悠亚| 亚洲三区在线观看无套内射| 国产精品久久一| 婷婷综合久久| 理论片大全免费理伦片| 欧美性极品xxxx做受| av中文字幕在线| 147欧美人体大胆444| 国产亚洲精品自拍| 久久久免费看片| 欧美本精品男人aⅴ天堂| 亚洲国产欧美日本视频| 亚洲国产日韩美| 国产成人免费在线| 亚洲天堂一区在线| 日韩在线视频播放| 国产精品久久久久av蜜臀| 午夜肉伦伦影院| 亚洲精品国产视频| 天堂a√中文在线| 91在线观看免费高清| 妖精视频成人观看www| 美国一级黄色录像| 精品91自产拍在线观看一区| 亚洲日本网址| www.好吊操| 亚洲国产电影在线观看| 亚洲av无码乱码国产精品久久| 日本高清久久天堂| 一区二区三区午夜探花| 亚洲精品视频大全| 日韩一区二区三区观看| 欧美freesex| 久久综合久久久久| 中文字幕国产一区| 欧美一级淫片aaaaaa| 国产日本欧美在线观看| 99在线精品视频在线观看| 欧美日韩午夜视频| 亚洲视屏在线播放| 国产人妖ts一区二区| www.污网站| 欧洲视频一区二区|